Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2021, Max Wipfli <max.wipfli@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <LibTest/TestCase.h>
9
10#include <AK/DeprecatedString.h>
11#include <AK/LexicalPath.h>
12
13TEST_CASE(relative_path)
14{
15 EXPECT_EQ(LexicalPath::relative_path("/tmp/abc.txt"sv, "/tmp"sv), "abc.txt"sv);
16 EXPECT_EQ(LexicalPath::relative_path("/tmp/abc.txt"sv, "/tmp/"sv), "abc.txt"sv);
17 EXPECT_EQ(LexicalPath::relative_path("/tmp/abc.txt"sv, "/"sv), "tmp/abc.txt"sv);
18 EXPECT_EQ(LexicalPath::relative_path("/tmp/abc.txt"sv, "/usr"sv), "../tmp/abc.txt"sv);
19
20 EXPECT_EQ(LexicalPath::relative_path("/tmp/foo.txt"sv, "tmp"sv), ""sv);
21 EXPECT_EQ(LexicalPath::relative_path("tmp/foo.txt"sv, "/tmp"sv), ""sv);
22
23 EXPECT_EQ(LexicalPath::relative_path("/tmp/foo/bar/baz.txt"sv, "/tmp/bar/foo/"sv), "../../foo/bar/baz.txt"sv);
24}
25
26TEST_CASE(regular_absolute_path)
27{
28 LexicalPath path("/home/anon/foo.txt");
29 EXPECT_EQ(path.string(), "/home/anon/foo.txt");
30 EXPECT_EQ(path.dirname(), "/home/anon");
31 EXPECT_EQ(path.basename(), "foo.txt");
32 EXPECT_EQ(path.title(), "foo");
33 EXPECT_EQ(path.extension(), "txt");
34 EXPECT(path.has_extension(".txt"sv));
35 EXPECT(path.has_extension("txt"sv));
36 EXPECT(!path.has_extension("txxt"sv));
37 EXPECT_EQ(path.parts_view().size(), 3u);
38 EXPECT_EQ(path.parts_view()[0], "home");
39 EXPECT_EQ(path.parts_view()[1], "anon");
40 EXPECT_EQ(path.parts_view()[2], "foo.txt");
41}
42
43TEST_CASE(regular_relative_path)
44{
45 LexicalPath path("anon/foo.txt");
46 EXPECT_EQ(path.dirname(), "anon");
47 EXPECT_EQ(path.basename(), "foo.txt");
48 EXPECT_EQ(path.parts_view().size(), 2u);
49 EXPECT_EQ(path.parts_view()[0], "anon");
50 EXPECT_EQ(path.parts_view()[1], "foo.txt");
51}
52
53TEST_CASE(single_dot)
54{
55 {
56 LexicalPath path("/home/./anon/foo.txt");
57 EXPECT_EQ(path.string(), "/home/anon/foo.txt");
58 }
59 {
60 LexicalPath path("./test.txt");
61 EXPECT_EQ(path.string(), "test.txt");
62 }
63 {
64 LexicalPath path("./../test.txt");
65 EXPECT_EQ(path.string(), "../test.txt");
66 }
67}
68
69TEST_CASE(relative_path_with_dotdot)
70{
71 LexicalPath path("anon/../../foo.txt");
72 EXPECT_EQ(path.string(), "../foo.txt");
73 EXPECT_EQ(path.dirname(), "..");
74 EXPECT_EQ(path.basename(), "foo.txt");
75 EXPECT_EQ(path.parts_view().size(), 2u);
76 EXPECT_EQ(path.parts_view()[0], "..");
77 EXPECT_EQ(path.parts_view()[1], "foo.txt");
78}
79
80TEST_CASE(absolute_path_with_dotdot)
81{
82 {
83 LexicalPath path("/test/../foo.txt");
84 EXPECT_EQ(path.string(), "/foo.txt");
85 }
86 {
87 LexicalPath path("/../../foo.txt");
88 EXPECT_EQ(path.string(), "/foo.txt");
89 }
90}
91
92TEST_CASE(more_dotdot_paths)
93{
94 EXPECT_EQ(LexicalPath::canonicalized_path("/home/user/../../not/home"), "/not/home");
95 EXPECT_EQ(LexicalPath::canonicalized_path("/../../../../"), "/");
96 EXPECT_EQ(LexicalPath::canonicalized_path("./../../../../"), "../../../..");
97 EXPECT_EQ(LexicalPath::canonicalized_path("../../../../../"), "../../../../..");
98}
99
100TEST_CASE(the_root_path)
101{
102 LexicalPath path("/");
103 EXPECT_EQ(path.dirname(), "/");
104 EXPECT_EQ(path.basename(), "/");
105 EXPECT_EQ(path.title(), "/");
106 EXPECT_EQ(path.parts_view().size(), 0u);
107}
108
109TEST_CASE(the_dot_path)
110{
111 LexicalPath path(".");
112 EXPECT_EQ(path.string(), ".");
113 EXPECT_EQ(path.dirname(), ".");
114 EXPECT_EQ(path.basename(), ".");
115 EXPECT_EQ(path.title(), ".");
116}
117
118TEST_CASE(double_slash)
119{
120 LexicalPath path("//home/anon/foo.txt");
121 EXPECT_EQ(path.string(), "/home/anon/foo.txt");
122}
123
124TEST_CASE(trailing_slash)
125{
126 LexicalPath path("/home/anon/");
127 EXPECT_EQ(path.string(), "/home/anon");
128 EXPECT_EQ(path.dirname(), "/home");
129 EXPECT_EQ(path.basename(), "anon");
130 EXPECT_EQ(path.parts_view().size(), 2u);
131}
132
133TEST_CASE(resolve_absolute_path)
134{
135 EXPECT_EQ(LexicalPath::absolute_path("/home/anon", "foo.txt"), "/home/anon/foo.txt");
136 EXPECT_EQ(LexicalPath::absolute_path("/home/anon/", "foo.txt"), "/home/anon/foo.txt");
137 EXPECT_EQ(LexicalPath::absolute_path("/home/anon", "././foo.txt"), "/home/anon/foo.txt");
138 EXPECT_EQ(LexicalPath::absolute_path("/home/anon/quux", "../foo.txt"), "/home/anon/foo.txt");
139 EXPECT_EQ(LexicalPath::absolute_path("/home/anon/quux", "../test/foo.txt"), "/home/anon/test/foo.txt");
140 EXPECT_EQ(LexicalPath::absolute_path("quux", "../test/foo.txt"), "test/foo.txt");
141 EXPECT_EQ(LexicalPath::absolute_path("quux", "../../test/foo.txt"), "../test/foo.txt");
142 EXPECT_EQ(LexicalPath::absolute_path("quux/bar", "../../test/foo.txt"), "test/foo.txt");
143 EXPECT_EQ(LexicalPath::absolute_path("quux/bar/", "../../test/foo.txt"), "test/foo.txt");
144}
145
146TEST_CASE(has_extension)
147{
148 {
149 LexicalPath path("/tmp/simple.png");
150 EXPECT(path.has_extension(".png"sv));
151 EXPECT(path.has_extension(".pnG"sv));
152 EXPECT(path.has_extension(".PNG"sv));
153 }
154
155 {
156 LexicalPath path("/TMP/SIMPLE.PNG");
157 EXPECT(path.has_extension(".png"sv));
158 EXPECT(path.has_extension(".pnG"sv));
159 EXPECT(path.has_extension(".PNG"sv));
160 }
161
162 {
163 LexicalPath path(".png");
164 EXPECT(path.has_extension(".png"sv));
165 }
166
167 {
168 LexicalPath path("png");
169 EXPECT_EQ(path.has_extension(".png"sv), false);
170 }
171}
172
173TEST_CASE(join)
174{
175 EXPECT_EQ(LexicalPath::join("anon"sv, "foo.txt"sv).string(), "anon/foo.txt"sv);
176 EXPECT_EQ(LexicalPath::join("/home"sv, "anon/foo.txt"sv).string(), "/home/anon/foo.txt"sv);
177 EXPECT_EQ(LexicalPath::join("/"sv, "foo.txt"sv).string(), "/foo.txt"sv);
178 EXPECT_EQ(LexicalPath::join("/home"sv, "anon"sv, "foo.txt"sv).string(), "/home/anon/foo.txt"sv);
179}
180
181TEST_CASE(append)
182{
183 LexicalPath path("/home/anon/");
184 auto new_path = path.append("foo.txt"sv);
185 EXPECT_EQ(new_path.string(), "/home/anon/foo.txt");
186}
187
188TEST_CASE(parent)
189{
190 {
191 LexicalPath path("/home/anon/foo.txt");
192 auto parent = path.parent();
193 EXPECT_EQ(parent.string(), "/home/anon");
194 }
195 {
196 LexicalPath path("anon/foo.txt");
197 auto parent = path.parent();
198 EXPECT_EQ(parent.string(), "anon");
199 }
200 {
201 LexicalPath path("foo.txt");
202 auto parent = path.parent();
203 EXPECT_EQ(parent.string(), ".");
204 auto parent_of_parent = parent.parent();
205 EXPECT_EQ(parent_of_parent.string(), "..");
206 }
207 {
208 LexicalPath path("/");
209 auto parent = path.parent();
210 EXPECT_EQ(parent.string(), "/");
211 }
212}
213
214TEST_CASE(is_child_of)
215{
216 {
217 LexicalPath parent("/a/parent/directory");
218 LexicalPath child("/a/parent/directory/a/child");
219 LexicalPath mismatching("/not/a/child/directory");
220 EXPECT(child.is_child_of(parent));
221 EXPECT(child.is_child_of(child));
222 EXPECT(parent.is_child_of(parent));
223 EXPECT(!parent.is_child_of(child));
224 EXPECT(!mismatching.is_child_of(parent));
225
226 EXPECT(parent.is_child_of(parent.parent()));
227 EXPECT(child.parent().parent().is_child_of(parent));
228 EXPECT(!child.parent().parent().parent().is_child_of(parent));
229 }
230 {
231 LexicalPath root("/");
232 EXPECT(LexicalPath("/").is_child_of(root));
233 EXPECT(LexicalPath("/any").is_child_of(root));
234 EXPECT(LexicalPath("/child/directory").is_child_of(root));
235 }
236 {
237 LexicalPath relative("folder");
238 LexicalPath relative_child("folder/sub");
239 LexicalPath absolute("/folder");
240 LexicalPath absolute_child("/folder/sub");
241 EXPECT(relative_child.is_child_of(relative));
242 EXPECT(absolute_child.is_child_of(absolute));
243
244 EXPECT(relative.is_child_of(absolute));
245 EXPECT(relative.is_child_of(absolute_child));
246 EXPECT(relative_child.is_child_of(absolute));
247 EXPECT(relative_child.is_child_of(absolute_child));
248
249 EXPECT(!absolute.is_child_of(relative));
250 EXPECT(!absolute_child.is_child_of(relative));
251 EXPECT(!absolute_child.is_child_of(relative_child));
252 }
253}