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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03 10 11 // XFAIL: LIBCXX-WINDOWS-FIXME 12 13 // <filesystem> 14 15 // path proximate(const path& p, error_code &ec) 16 // path proximate(const path& p, const path& base = current_path()) 17 // path proximate(const path& p, const path& base, error_code& ec); 18 19 #include "filesystem_include.h" 20 #include <cassert> 21 #include <cstdio> 22 23 #include "test_macros.h" 24 #include "count_new.h" 25 #include "rapid-cxx-test.h" 26 #include "filesystem_test_helper.h" 27 28 29 static int count_path_elems(const fs::path& p) { 30 int count = 0; 31 for (auto& elem : p) { 32 if (elem != "/" && elem != "") 33 ++count; 34 } 35 return count; 36 } 37 38 TEST_SUITE(filesystem_proximate_path_test_suite) 39 40 41 TEST_CASE(signature_test) 42 { 43 using fs::path; 44 const path p; ((void)p); 45 std::error_code ec; ((void)ec); 46 ASSERT_NOT_NOEXCEPT(proximate(p)); 47 ASSERT_NOT_NOEXCEPT(proximate(p, p)); 48 ASSERT_NOT_NOEXCEPT(proximate(p, ec)); 49 ASSERT_NOT_NOEXCEPT(proximate(p, p, ec)); 50 } 51 52 TEST_CASE(basic_test) { 53 using fs::path; 54 const path cwd = fs::current_path(); 55 const path parent_cwd = cwd.parent_path(); 56 const path curdir = cwd.filename(); 57 TEST_REQUIRE(!cwd.native().empty()); 58 int cwd_depth = count_path_elems(cwd); 59 path dot_dot_to_root; 60 for (int i=0; i < cwd_depth; ++i) 61 dot_dot_to_root /= ".."; 62 path relative_cwd = cwd.native().substr(1); 63 // clang-format off 64 struct { 65 fs::path input; 66 fs::path base; 67 fs::path expect; 68 } TestCases[] = { 69 {"", "", "."}, 70 {cwd, "a", ".."}, 71 {parent_cwd, "a", "../.."}, 72 {"a", cwd, "a"}, 73 {"a", parent_cwd, curdir / "a"}, 74 {"/", "a", dot_dot_to_root / ".."}, 75 {"/", "a/b", dot_dot_to_root / "../.."}, 76 {"/", "a/b/", dot_dot_to_root / "../.."}, 77 {"a", "/", relative_cwd / "a"}, 78 {"a/b", "/", relative_cwd / "a/b"}, 79 {"a", "/net", ".." / relative_cwd / "a"}, 80 {"//foo/", "//foo", "."}, 81 {"//foo", "//foo/", "."}, 82 {"//foo", "//foo", "."}, 83 {"//foo/", "//foo/", "."}, 84 {"//base", "a", dot_dot_to_root / "../base"}, 85 {"a", "a", "."}, 86 {"a/b", "a/b", "."}, 87 {"a/b/c/", "a/b/c/", "."}, 88 {"//foo/a/b", "//foo/a/b", "."}, 89 {"/a/d", "/a/b/c", "../../d"}, 90 {"/a/b/c", "/a/d", "../b/c"}, 91 {"a/b/c", "a", "b/c"}, 92 {"a/b/c", "a/b/c/x/y", "../.."}, 93 {"a/b/c", "a/b/c", "."}, 94 {"a/b", "c/d", "../../a/b"} 95 }; 96 // clang-format on 97 int ID = 0; 98 for (auto& TC : TestCases) { 99 ++ID; 100 std::error_code ec = GetTestEC(); 101 fs::path p(TC.input); 102 const fs::path output = fs::proximate(p, TC.base, ec); 103 if (ec) { 104 TEST_CHECK(!ec); 105 std::fprintf(stderr, "TEST CASE #%d FAILED:\n" 106 " Input: '%s'\n" 107 " Base: '%s'\n" 108 " Expected: '%s'\n", 109 ID, TC.input.string().c_str(), TC.base.string().c_str(), 110 TC.expect.string().c_str()); 111 } else if (!PathEq(output, TC.expect)) { 112 TEST_CHECK(PathEq(output, TC.expect)); 113 114 const path canon_input = fs::weakly_canonical(TC.input); 115 const path canon_base = fs::weakly_canonical(TC.base); 116 const path lexically_p = canon_input.lexically_proximate(canon_base); 117 std::fprintf(stderr, "TEST CASE #%d FAILED:\n" 118 " Input: '%s'\n" 119 " Base: '%s'\n" 120 " Expected: '%s'\n" 121 " Output: '%s'\n" 122 " Lex Prox: '%s'\n" 123 " Canon Input: '%s'\n" 124 " Canon Base: '%s'\n", 125 ID, TC.input.string().c_str(), TC.base.string().c_str(), 126 TC.expect.string().c_str(), output.string().c_str(), 127 lexically_p.string().c_str(), canon_input.string().c_str(), 128 canon_base.string().c_str()); 129 } 130 } 131 } 132 133 TEST_SUITE_END() 134