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