1 //===----------------------------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: c++98, c++03
11 
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_include.hpp"
19 #include <type_traits>
20 #include <vector>
21 #include <iostream>
22 #include <cassert>
23 
24 #include "test_macros.h"
25 #include "test_iterators.h"
26 #include "count_new.hpp"
27 #include "rapid-cxx-test.hpp"
28 #include "filesystem_test_helper.hpp"
29 
30 
count_path_elems(const fs::path & p)31 static int count_path_elems(const fs::path& p) {
32   int count = 0;
33   for (auto& elem : p) {
34     if (elem != "/" && elem != "")
35       ++count;
36   }
37   return count;
38 }
39 
40 TEST_SUITE(filesystem_proximate_path_test_suite)
41 
42 
TEST_CASE(signature_test)43 TEST_CASE(signature_test)
44 {
45     using fs::path;
46     const path p; ((void)p);
47     std::error_code ec; ((void)ec);
48     ASSERT_NOT_NOEXCEPT(proximate(p));
49     ASSERT_NOT_NOEXCEPT(proximate(p, p));
50     ASSERT_NOT_NOEXCEPT(proximate(p, ec));
51     ASSERT_NOT_NOEXCEPT(proximate(p, p, ec));
52 }
53 
TEST_CASE(basic_test)54 TEST_CASE(basic_test) {
55   using fs::path;
56   const path cwd = fs::current_path();
57   const path parent_cwd = cwd.parent_path();
58   const path curdir = cwd.filename();
59   TEST_REQUIRE(!cwd.native().empty());
60   int cwd_depth = count_path_elems(cwd);
61   path dot_dot_to_root;
62   for (int i=0; i < cwd_depth; ++i)
63     dot_dot_to_root /= "..";
64   path relative_cwd = cwd.native().substr(1);
65   // clang-format off
66   struct {
67     std::string input;
68     std::string base;
69     std::string expect;
70   } TestCases[] = {
71       {"", "", "."},
72       {cwd, "a", ".."},
73       {parent_cwd, "a", "../.."},
74       {"a", cwd, "a"},
75 #if !defined(__ANDROID__)
76       // Android tests are run via a RemoteExecutor, where the parent directory
77       // is a temporary directory with no fixed name.
78       {"a", parent_cwd, "fs.op.proximate/a"},
79 #endif
80       {"/", "a", dot_dot_to_root / ".."},
81       {"/", "a/b", dot_dot_to_root / "../.."},
82       {"/", "a/b/", dot_dot_to_root / "../.."},
83       {"a", "/", relative_cwd / "a"},
84       {"a/b", "/", relative_cwd / "a/b"},
85       {"a", "/net", ".." / relative_cwd / "a"},
86       {"//foo/", "//foo", "."},
87       {"//foo", "//foo/", "."},
88       {"//foo", "//foo", "."},
89       {"//foo/", "//foo/", "."},
90       {"//base", "a", dot_dot_to_root / "../base"},
91       {"a", "a", "."},
92       {"a/b", "a/b", "."},
93       {"a/b/c/", "a/b/c/", "."},
94       {"//foo/a/b", "//foo/a/b", "."},
95       {"/a/d", "/a/b/c", "../../d"},
96       {"/a/b/c", "/a/d", "../b/c"},
97       {"a/b/c", "a", "b/c"},
98       {"a/b/c", "a/b/c/x/y", "../.."},
99       {"a/b/c", "a/b/c", "."},
100       {"a/b", "c/d", "../../a/b"}
101   };
102   // clang-format on
103   int ID = 0;
104   for (auto& TC : TestCases) {
105     ++ID;
106     std::error_code ec = GetTestEC();
107     fs::path p(TC.input);
108     const fs::path output = fs::proximate(p, TC.base, ec);
109     if (ec) {
110       TEST_CHECK(!ec);
111       std::cerr << "TEST CASE #" << ID << " FAILED: \n";
112       std::cerr << "  Input: '" << TC.input << "'\n";
113       std::cerr << "  Base: '" << TC.base << "'\n";
114       std::cerr << "  Expected: '" << TC.expect << "'\n";
115 
116       std::cerr << std::endl;
117     } else if (!PathEq(output, TC.expect)) {
118       TEST_CHECK(PathEq(output, TC.expect));
119 
120       const path canon_input = fs::weakly_canonical(TC.input);
121       const path canon_base = fs::weakly_canonical(TC.base);
122       const path lexically_p = canon_input.lexically_proximate(canon_base);
123       std::cerr << "TEST CASE #" << ID << " FAILED: \n";
124       std::cerr << "  Input: '" << TC.input << "'\n";
125       std::cerr << "  Base: '" << TC.base << "'\n";
126       std::cerr << "  Expected: '" << TC.expect << "'\n";
127       std::cerr << "  Output:   '" << output.native() << "'\n";
128       std::cerr << "  Lex Prox: '" << lexically_p.native() << "'\n";
129       std::cerr << "  Canon Input: " <<  canon_input << "\n";
130       std::cerr << "  Canon Base: " << canon_base << "\n";
131 
132       std::cerr << std::endl;
133     }
134   }
135 }
136 
137 TEST_SUITE_END()
138