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: availability-filesystem-missing |
11 | |
12 | // <filesystem> |
13 | |
14 | // class path |
15 | |
16 | // path lexically_normal() const; |
17 | |
18 | #include <filesystem> |
19 | #include <string> |
20 | |
21 | #include "../../path_helper.h" |
22 | #include "count_new.h" |
23 | #include "test_macros.h" |
24 | #include "assert_macros.h" |
25 | #include "concat_macros.h" |
26 | namespace fs = std::filesystem; |
27 | |
28 | int main(int, char**) { |
29 | // clang-format off |
30 | struct { |
31 | std::string input; |
32 | std::string expect; |
33 | } TestCases[] = { |
34 | {.input: "" , .expect: "" }, |
35 | {.input: "/a/b/c" , .expect: "/a/b/c" }, |
36 | {.input: "/a/b//c" , .expect: "/a/b/c" }, |
37 | {.input: "foo/./bar/.." , .expect: "foo/" }, |
38 | {.input: "foo/.///bar/../" , .expect: "foo/" }, |
39 | {.input: "/a/b/" , .expect: "/a/b/" }, |
40 | {.input: "a/b" , .expect: "a/b" }, |
41 | {.input: "a/b/." , .expect: "a/b/" }, |
42 | {.input: "a/b/./" , .expect: "a/b/" }, |
43 | {.input: "a/.." , .expect: "." }, |
44 | {.input: "." , .expect: "." }, |
45 | {.input: "./" , .expect: "." }, |
46 | {.input: "./." , .expect: "." }, |
47 | {.input: "./.." , .expect: ".." }, |
48 | {.input: ".." , .expect: ".." }, |
49 | {.input: "../.." , .expect: "../.." }, |
50 | {.input: "/../" , .expect: "/" }, |
51 | {.input: "/../.." , .expect: "/" }, |
52 | {.input: "/../../" , .expect: "/" }, |
53 | {.input: ".." , .expect: ".." }, |
54 | {.input: "../" , .expect: ".." }, |
55 | {.input: "/a/b/c/../" , .expect: "/a/b/" }, |
56 | {.input: "/a/b/./" , .expect: "/a/b/" }, |
57 | {.input: "/a/b/c/../d" , .expect: "/a/b/d" }, |
58 | {.input: "/a/b/c/../d/" , .expect: "/a/b/d/" }, |
59 | #ifdef _WIN32 |
60 | {"//a/" , "//a/" }, |
61 | {"//a/b/" , "//a/b/" }, |
62 | {"//a/b/." , "//a/b/" }, |
63 | {"//a/.." , "//a/" }, |
64 | #else |
65 | {.input: "//a/" , .expect: "/a/" }, |
66 | {.input: "//a/b/" , .expect: "/a/b/" }, |
67 | {.input: "//a/b/." , .expect: "/a/b/" }, |
68 | {.input: "//a/.." , .expect: "/" }, |
69 | #endif |
70 | ///===---------------------------------------------------------------===// |
71 | /// Tests specifically for the clauses under [fs.path.generic]p6 |
72 | ///===---------------------------------------------------------------===// |
73 | // p1: If the path is empty, stop. |
74 | {.input: "" , .expect: "" }, |
75 | // p2: Replace each slash character in the root-name with a preferred |
76 | // separator. |
77 | {.input: "NO_ROOT_NAME_ON_LINUX" , .expect: "NO_ROOT_NAME_ON_LINUX" }, |
78 | // p3: Replace each directory-separator with a preferred-separator. |
79 | // [ Note: The generic pathname grammar ([fs.path.generic]) defines |
80 | // directory-separator as one or more slashes and preferred-separators. |
81 | // - end note ] |
82 | {.input: "/" , .expect: "/" }, |
83 | {.input: "//" , .expect: "/" }, |
84 | {.input: "///" , .expect: "/" }, |
85 | {.input: "a/b" , .expect: "a/b" }, |
86 | {.input: "a//b" , .expect: "a/b" }, |
87 | {.input: "a///b" , .expect: "a/b" }, |
88 | {.input: "a/b/" , .expect: "a/b/" }, |
89 | {.input: "a/b//" , .expect: "a/b/" }, |
90 | {.input: "a/b///" , .expect: "a/b/" }, |
91 | {.input: "///a////b//////" , .expect: "/a/b/" }, |
92 | // p4: Remove each dot filename and any immediately following directory |
93 | // separators |
94 | {.input: "foo/." , .expect: "foo/" }, |
95 | {.input: "foo/./bar/." , .expect: "foo/bar/" }, |
96 | {.input: "./foo/././bar/./" , .expect: "foo/bar/" }, |
97 | {.input: ".///foo//.////./bar/.///" , .expect: "foo/bar/" }, |
98 | // p5: As long as any appear, remove a non-dot-dot filename immediately |
99 | // followed by a directory-separator and a dot-dot filename, along with |
100 | // any immediately following directory separator. |
101 | {.input: "foo/.." , .expect: "." }, |
102 | {.input: "foo/../" , .expect: "." }, |
103 | {.input: "foo/bar/.." , .expect: "foo/" }, |
104 | {.input: "foo/bar/../" , .expect: "foo/" }, |
105 | {.input: "foo/bar/../.." , .expect: "." }, |
106 | {.input: "foo/bar/../../" , .expect: "." }, |
107 | {.input: "foo/bar/baz/../.." , .expect: "foo/" }, |
108 | {.input: "foo/bar/baz/../../" , .expect: "foo/" }, |
109 | {.input: "foo/bar/./.." , .expect: "foo/" }, |
110 | {.input: "foo/bar/./../" , .expect: "foo/" }, |
111 | // p6: If there is a root-directory, remove all dot-dot filenames and any |
112 | // directory-separators immediately following them. [ Note: These dot-dot |
113 | // filenames attempt to refer to nonexistent parent directories. - end note ] |
114 | {.input: "/.." , .expect: "/" }, |
115 | {.input: "/../" , .expect: "/" }, |
116 | {.input: "/foo/../.." , .expect: "/" }, |
117 | {.input: "/../foo" , .expect: "/foo" }, |
118 | {.input: "/../foo/../.." , .expect: "/" }, |
119 | // p7: If the last filename is dot-dot, remove any trailing |
120 | // directory-separator. |
121 | {.input: "../" , .expect: ".." }, |
122 | {.input: "../../" , .expect: "../.." }, |
123 | {.input: "foo/../bar/../..///" , .expect: ".." }, |
124 | {.input: "foo/../bar/..//..///../" , .expect: "../.." }, |
125 | // p8: If the path is empty, add a dot |
126 | {.input: "." , .expect: "." }, |
127 | {.input: "./" , .expect: "." }, |
128 | {.input: "foo/.." , .expect: "." } |
129 | }; |
130 | // clang-format on |
131 | for (auto& TC : TestCases) { |
132 | fs::path p(TC.input); |
133 | const fs::path output = p.lexically_normal(); |
134 | fs::path expect(TC.expect); |
135 | expect.make_preferred(); |
136 | |
137 | TEST_REQUIRE( |
138 | PathEq(LHS: output, RHS: expect), |
139 | TEST_WRITE_CONCATENATED("Input: " , TC.input, "\nExpected: " , expect.string(), "\nOutput: " , output.string())); |
140 | } |
141 | return 0; |
142 | } |
143 | |