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, c++11, c++14
10// UNSUPPORTED: no-filesystem
11// UNSUPPORTED: availability-filesystem-missing
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>
20#include <cassert>
21
22#include "assert_macros.h"
23#include "concat_macros.h"
24#include "test_macros.h"
25#include "count_new.h"
26#include "filesystem_test_helper.h"
27#include "../../class.path/path_helper.h"
28namespace fs = std::filesystem;
29
30static int count_path_elems(const fs::path& p) {
31 int count = 0;
32 for (auto&& elem : p) {
33 if (elem != p.root_name() && elem != "/" && elem != "")
34 ++count;
35 }
36 return count;
37}
38
39static void signature_test() {
40 using fs::path;
41 const path p;
42 ((void)p);
43 std::error_code ec;
44 ((void)ec);
45 ASSERT_NOT_NOEXCEPT(proximate(p: p));
46 ASSERT_NOT_NOEXCEPT(proximate(p: p, base: p));
47 ASSERT_NOT_NOEXCEPT(proximate(p: p, ec&: ec));
48 ASSERT_NOT_NOEXCEPT(proximate(p: p, base: p, ec&: ec));
49}
50
51static void basic_test() {
52 using fs::path;
53 const path cwd = fs::current_path();
54 const path parent_cwd = cwd.parent_path();
55 const path curdir = cwd.filename();
56 assert(!cwd.native().empty());
57 int cwd_depth = count_path_elems(p: cwd);
58 path dot_dot_to_root;
59 for (int i = 0; i < cwd_depth; ++i)
60 dot_dot_to_root /= "..";
61 path relative_cwd = cwd.native().substr(pos: cwd.root_path().native().size());
62 // clang-format off
63 struct {
64 fs::path input;
65 fs::path base;
66 fs::path expect;
67 } TestCases[] = {
68 {.input: "", .base: "", .expect: "."},
69 {.input: cwd, .base: "a", .expect: ".."},
70 {.input: parent_cwd, .base: "a", .expect: "../.."},
71 {.input: "a", .base: cwd, .expect: "a"},
72 {.input: "a", .base: parent_cwd, .expect: curdir / "a"},
73 {.input: "/", .base: "a", .expect: dot_dot_to_root / ".."},
74 {.input: "/", .base: "a/b", .expect: dot_dot_to_root / "../.."},
75 {.input: "/", .base: "a/b/", .expect: dot_dot_to_root / "../.."},
76 {.input: "a", .base: "/", .expect: relative_cwd / "a"},
77 {.input: "a/b", .base: "/", .expect: relative_cwd / "a/b"},
78 {.input: "a", .base: "/net", .expect: ".." / relative_cwd / "a"},
79#ifdef _WIN32
80 {"//foo/", "//foo", "//foo/"},
81 {"//foo", "//foo/", "//foo"},
82#else
83 {.input: "//foo/", .base: "//foo", .expect: "."},
84 {.input: "//foo", .base: "//foo/", .expect: "."},
85#endif
86 {.input: "//foo", .base: "//foo", .expect: "."},
87 {.input: "//foo/", .base: "//foo/", .expect: "."},
88#ifdef _WIN32
89 {"//foo", "a", "//foo"},
90 {"//foo/a", "//bar", "//foo/a"},
91 {"//foo/a", "//bar/", "//foo/a"},
92 {"//foo/a", "b", "//foo/a"},
93 {"//foo/a", "/b", "//foo/a"},
94 {"//foo/a", "//bar/b", "//foo/a"},
95 // Using X: instead of C: to avoid influence from the CWD being under C:
96 {"X:/a", "X:/b", "../a"},
97 {"X:/a", "X:b", "X:/a"},
98 {"X:/a", "Y:/a", "X:/a"},
99 {"X:/a", "Y:/b", "X:/a"},
100 {"X:/a", "Y:b", "X:/a"},
101 {"X:a", "X:/b", "X:a"},
102 {"X:a", "X:b", "../a"},
103 {"X:a", "Y:/a", "X:a"},
104 {"X:a", "Y:/b", "X:a"},
105 {"X:a", "Y:b", "X:a"},
106#else
107 {.input: "//foo", .base: "a", .expect: dot_dot_to_root / "../foo"},
108 {.input: "//foo/a", .base: "//bar", .expect: "../foo/a"},
109 {.input: "//foo/a", .base: "//bar/", .expect: "../foo/a"},
110 {.input: "//foo/a", .base: "b", .expect: dot_dot_to_root / "../foo/a"},
111 {.input: "//foo/a", .base: "/b", .expect: "../foo/a"},
112 {.input: "//foo/a", .base: "//bar/b", .expect: "../../foo/a"},
113 {.input: "X:/a", .base: "X:/b", .expect: "../a"},
114 {.input: "X:/a", .base: "X:b", .expect: "../X:/a"},
115 {.input: "X:/a", .base: "Y:/a", .expect: "../../X:/a"},
116 {.input: "X:/a", .base: "Y:/b", .expect: "../../X:/a"},
117 {.input: "X:/a", .base: "Y:b", .expect: "../X:/a"},
118 {.input: "X:a", .base: "X:/b", .expect: "../../X:a"},
119 {.input: "X:a", .base: "X:b", .expect: "../X:a"},
120 {.input: "X:a", .base: "Y:/a", .expect: "../../X:a"},
121 {.input: "X:a", .base: "Y:/b", .expect: "../../X:a"},
122 {.input: "X:a", .base: "Y:b", .expect: "../X:a"},
123#endif
124 {.input: "a", .base: "a", .expect: "."},
125 {.input: "a/b", .base: "a/b", .expect: "."},
126 {.input: "a/b/c/", .base: "a/b/c/", .expect: "."},
127 {.input: "//foo/a/b", .base: "//foo/a/b", .expect: "."},
128 {.input: "/a/d", .base: "/a/b/c", .expect: "../../d"},
129 {.input: "/a/b/c", .base: "/a/d", .expect: "../b/c"},
130 {.input: "a/b/c", .base: "a", .expect: "b/c"},
131 {.input: "a/b/c", .base: "a/b/c/x/y", .expect: "../.."},
132 {.input: "a/b/c", .base: "a/b/c", .expect: "."},
133 {.input: "a/b", .base: "c/d", .expect: "../../a/b"}
134 };
135 // clang-format on
136 for (auto& TC : TestCases) {
137 std::error_code ec = GetTestEC();
138 fs::path p = TC.input;
139 const fs::path output = fs::proximate(p: p, base: TC.base, ec&: ec);
140 fs::path expect = TC.expect;
141 expect.make_preferred();
142 TEST_REQUIRE(!ec,
143 TEST_WRITE_CONCATENATED(
144 "Input: ", TC.input.string(), "\nBase: ", TC.base.string(), "\nExpected: ", expect.string()));
145
146 const path canon_input = fs::weakly_canonical(p: TC.input);
147 const path canon_base = fs::weakly_canonical(p: TC.base);
148 const path lexically_p = canon_input.lexically_proximate(base: canon_base);
149 TEST_REQUIRE(
150 PathEq(LHS: output, RHS: expect),
151 TEST_WRITE_CONCATENATED(
152 "Input: ",
153 TC.input.string(),
154 "\nBase: ",
155 TC.base.string(),
156 "\nExpected: ",
157 expect.string(),
158 "\nOutput: ",
159 output.string(),
160 "\nLex Prox: ",
161 lexically_p.string(),
162 "\nCanon Input: ",
163 canon_input.string(),
164 "\nCanon Base: ",
165 canon_base.string()));
166 }
167}
168
169int main(int, char**) {
170 signature_test();
171 basic_test();
172
173 return 0;
174}
175

source code of libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.proximate/proximate.pass.cpp