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