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
count_path_elems(const fs::path & p)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
TEST_CASE(signature_test)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
TEST_CASE(basic_test)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 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 {"//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.string().c_str(), TC.base.string().c_str(),
108 TC.expect.string().c_str());
109 } else if (!PathEq(output, TC.expect)) {
110 TEST_CHECK(PathEq(output, TC.expect));
111
112 const path canon_input = fs::weakly_canonical(TC.input);
113 const path canon_base = fs::weakly_canonical(TC.base);
114 const path lexically_p = canon_input.lexically_proximate(canon_base);
115 std::fprintf(stderr, "TEST CASE #%d FAILED:\n"
116 " Input: '%s'\n"
117 " Base: '%s'\n"
118 " Expected: '%s'\n"
119 " Output: '%s'\n"
120 " Lex Prox: '%s'\n"
121 " Canon Input: '%s'\n"
122 " Canon Base: '%s'\n",
123 ID, TC.input.string().c_str(), TC.base.string().c_str(),
124 TC.expect.string().c_str(), output.string().c_str(),
125 lexically_p.string().c_str(), canon_input.string().c_str(),
126 canon_base.string().c_str());
127 }
128 }
129 }
130
131 TEST_SUITE_END()
132