174 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410// UNSUPPORTED: no-filesystem11 12// <filesystem>13 14// path proximate(const path& p, error_code &ec)15// path proximate(const path& p, const path& base = current_path())16// path proximate(const path& p, const path& base, error_code& ec);17 18#include <filesystem>19#include <cassert>20 21#include "assert_macros.h"22#include "concat_macros.h"23#include "test_macros.h"24#include "count_new.h"25#include "filesystem_test_helper.h"26#include "../../class.path/path_helper.h"27namespace fs = std::filesystem;28 29static int count_path_elems(const fs::path& p) {30 int count = 0;31 for (auto&& elem : p) {32 if (elem != p.root_name() && elem != "/" && elem != "")33 ++count;34 }35 return count;36}37 38static void signature_test() {39 using fs::path;40 const path p;41 ((void)p);42 std::error_code ec;43 ((void)ec);44 ASSERT_NOT_NOEXCEPT(proximate(p));45 ASSERT_NOT_NOEXCEPT(proximate(p, p));46 ASSERT_NOT_NOEXCEPT(proximate(p, ec));47 ASSERT_NOT_NOEXCEPT(proximate(p, p, ec));48}49 50static void basic_test() {51 using fs::path;52 const path cwd = fs::current_path();53 const path parent_cwd = cwd.parent_path();54 const path curdir = cwd.filename();55 assert(!cwd.native().empty());56 int cwd_depth = count_path_elems(cwd);57 path dot_dot_to_root;58 for (int i = 0; i < cwd_depth; ++i)59 dot_dot_to_root /= "..";60 path relative_cwd = cwd.native().substr(cwd.root_path().native().size());61 // clang-format off62 struct {63 fs::path input;64 fs::path base;65 fs::path expect;66 } TestCases[] = {67 {"", "", "."},68 {cwd, "a", ".."},69 {parent_cwd, "a", "../.."},70 {"a", cwd, "a"},71 {"a", parent_cwd, curdir / "a"},72 {"/", "a", dot_dot_to_root / ".."},73 {"/", "a/b", dot_dot_to_root / "../.."},74 {"/", "a/b/", dot_dot_to_root / "../.."},75 {"a", "/", relative_cwd / "a"},76 {"a/b", "/", relative_cwd / "a/b"},77 {"a", "/net", ".." / relative_cwd / "a"},78#ifdef _WIN3279 {"//foo/", "//foo", "//foo/"},80 {"//foo", "//foo/", "//foo"},81#else82 {"//foo/", "//foo", "."},83 {"//foo", "//foo/", "."},84#endif85 {"//foo", "//foo", "."},86 {"//foo/", "//foo/", "."},87#ifdef _WIN3288 {"//foo", "a", "//foo"},89 {"//foo/a", "//bar", "//foo/a"},90 {"//foo/a", "//bar/", "//foo/a"},91 {"//foo/a", "b", "//foo/a"},92 {"//foo/a", "/b", "//foo/a"},93 {"//foo/a", "//bar/b", "//foo/a"},94 // Using X: instead of C: to avoid influence from the CWD being under C:95 {"X:/a", "X:/b", "../a"},96 {"X:/a", "X:b", "X:/a"},97 {"X:/a", "Y:/a", "X:/a"},98 {"X:/a", "Y:/b", "X:/a"},99 {"X:/a", "Y:b", "X:/a"},100 {"X:a", "X:/b", "X:a"},101 {"X:a", "X:b", "../a"},102 {"X:a", "Y:/a", "X:a"},103 {"X:a", "Y:/b", "X:a"},104 {"X:a", "Y:b", "X:a"},105#else106 {"//foo", "a", dot_dot_to_root / "../foo"},107 {"//foo/a", "//bar", "../foo/a"},108 {"//foo/a", "//bar/", "../foo/a"},109 {"//foo/a", "b", dot_dot_to_root / "../foo/a"},110 {"//foo/a", "/b", "../foo/a"},111 {"//foo/a", "//bar/b", "../../foo/a"},112 {"X:/a", "X:/b", "../a"},113 {"X:/a", "X:b", "../X:/a"},114 {"X:/a", "Y:/a", "../../X:/a"},115 {"X:/a", "Y:/b", "../../X:/a"},116 {"X:/a", "Y:b", "../X:/a"},117 {"X:a", "X:/b", "../../X:a"},118 {"X:a", "X:b", "../X:a"},119 {"X:a", "Y:/a", "../../X:a"},120 {"X:a", "Y:/b", "../../X:a"},121 {"X:a", "Y:b", "../X:a"},122#endif123 {"a", "a", "."},124 {"a/b", "a/b", "."},125 {"a/b/c/", "a/b/c/", "."},126 {"//foo/a/b", "//foo/a/b", "."},127 {"/a/d", "/a/b/c", "../../d"},128 {"/a/b/c", "/a/d", "../b/c"},129 {"a/b/c", "a", "b/c"},130 {"a/b/c", "a/b/c/x/y", "../.."},131 {"a/b/c", "a/b/c", "."},132 {"a/b", "c/d", "../../a/b"}133 };134 // clang-format on135 for (auto& TC : TestCases) {136 std::error_code ec = GetTestEC();137 fs::path p = TC.input;138 const fs::path output = fs::proximate(p, TC.base, ec);139 fs::path expect = TC.expect;140 expect.make_preferred();141 TEST_REQUIRE(!ec,142 TEST_WRITE_CONCATENATED(143 "Input: ", TC.input.string(), "\nBase: ", TC.base.string(), "\nExpected: ", expect.string()));144 145 const path canon_input = fs::weakly_canonical(TC.input);146 const path canon_base = fs::weakly_canonical(TC.base);147 const path lexically_p = canon_input.lexically_proximate(canon_base);148 TEST_REQUIRE(149 PathEq(output, expect),150 TEST_WRITE_CONCATENATED(151 "Input: ",152 TC.input.string(),153 "\nBase: ",154 TC.base.string(),155 "\nExpected: ",156 expect.string(),157 "\nOutput: ",158 output.string(),159 "\nLex Prox: ",160 lexically_p.string(),161 "\nCanon Input: ",162 canon_input.string(),163 "\nCanon Base: ",164 canon_base.string()));165 }166}167 168int main(int, char**) {169 signature_test();170 basic_test();171 172 return 0;173}174