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 // <filesystem> 12 13 // path proximate(const path& p, error_code &ec) 14 // path proximate(const path& p, const path& base = current_path()) 15 // path proximate(const path& p, const path& base, error_code& ec); 16 17 #include "filesystem_include.h" 18 #include <cassert> 19 #include <cstdio> 20 21 #include "test_macros.h" 22 #include "count_new.h" 23 #include "rapid-cxx-test.h" 24 #include "filesystem_test_helper.h" 25 26 27 static int count_path_elems(const fs::path& p) { 28 int count = 0; 29 for (auto& elem : p) { 30 if (elem != "/" && elem != "") 31 ++count; 32 } 33 return count; 34 } 35 36 TEST_SUITE(filesystem_proximate_path_test_suite) 37 38 39 TEST_CASE(signature_test) 40 { 41 using fs::path; 42 const path p; ((void)p); 43 std::error_code ec; ((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 50 TEST_CASE(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 TEST_REQUIRE(!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(1); 61 // clang-format off 62 struct { 63 std::string input; 64 std::string base; 65 std::string 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 {"//foo/", "//foo", "."}, 79 {"//foo", "//foo/", "."}, 80 {"//foo", "//foo", "."}, 81 {"//foo/", "//foo/", "."}, 82 {"//base", "a", dot_dot_to_root / "../base"}, 83 {"a", "a", "."}, 84 {"a/b", "a/b", "."}, 85 {"a/b/c/", "a/b/c/", "."}, 86 {"//foo/a/b", "//foo/a/b", "."}, 87 {"/a/d", "/a/b/c", "../../d"}, 88 {"/a/b/c", "/a/d", "../b/c"}, 89 {"a/b/c", "a", "b/c"}, 90 {"a/b/c", "a/b/c/x/y", "../.."}, 91 {"a/b/c", "a/b/c", "."}, 92 {"a/b", "c/d", "../../a/b"} 93 }; 94 // clang-format on 95 int ID = 0; 96 for (auto& TC : TestCases) { 97 ++ID; 98 std::error_code ec = GetTestEC(); 99 fs::path p(TC.input); 100 const fs::path output = fs::proximate(p, TC.base, ec); 101 if (ec) { 102 TEST_CHECK(!ec); 103 std::fprintf(stderr, "TEST CASE #%d FAILED:\n" 104 " Input: '%s'\n" 105 " Base: '%s'\n" 106 " Expected: '%s'\n", 107 ID, TC.input.c_str(), TC.base.c_str(), TC.expect.c_str()); 108 } else if (!PathEq(output, TC.expect)) { 109 TEST_CHECK(PathEq(output, TC.expect)); 110 111 const path canon_input = fs::weakly_canonical(TC.input); 112 const path canon_base = fs::weakly_canonical(TC.base); 113 const path lexically_p = canon_input.lexically_proximate(canon_base); 114 std::fprintf(stderr, "TEST CASE #%d FAILED:\n" 115 " Input: '%s'\n" 116 " Base: '%s'\n" 117 " Expected: '%s'\n" 118 " Output: '%s'\n" 119 " Lex Prox: '%s'\n" 120 " Canon Input: '%s'\n" 121 " Canon Base: '%s'\n", 122 ID, TC.input.c_str(), TC.base.c_str(), TC.expect.c_str(), 123 output.native().c_str(), lexically_p.native().c_str(), 124 canon_input.c_str(), canon_base.c_str()); 125 } 126 } 127 } 128 129 TEST_SUITE_END() 130