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