1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gn/filesystem_utils.h"
6
7 #include <thread>
8
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "gn/target.h"
15 #include "util/build_config.h"
16 #include "util/test/test.h"
17
TEST(FilesystemUtils,FileExtensionOffset)18 TEST(FilesystemUtils, FileExtensionOffset) {
19 EXPECT_EQ(std::string::npos, FindExtensionOffset(""));
20 EXPECT_EQ(std::string::npos, FindExtensionOffset("foo/bar/baz"));
21 EXPECT_EQ(4u, FindExtensionOffset("foo."));
22 EXPECT_EQ(4u, FindExtensionOffset("f.o.bar"));
23 EXPECT_EQ(std::string::npos, FindExtensionOffset("foo.bar/"));
24 EXPECT_EQ(std::string::npos, FindExtensionOffset("foo.bar/baz"));
25 }
26
TEST(FilesystemUtils,FindExtension)27 TEST(FilesystemUtils, FindExtension) {
28 std::string input;
29 EXPECT_EQ("", FindExtension(&input));
30 input = "foo/bar/baz";
31 EXPECT_EQ("", FindExtension(&input));
32 input = "foo.";
33 EXPECT_EQ("", FindExtension(&input));
34 input = "f.o.bar";
35 EXPECT_EQ("bar", FindExtension(&input));
36 input = "foo.bar/";
37 EXPECT_EQ("", FindExtension(&input));
38 input = "foo.bar/baz";
39 EXPECT_EQ("", FindExtension(&input));
40 }
41
TEST(FilesystemUtils,FindFilenameOffset)42 TEST(FilesystemUtils, FindFilenameOffset) {
43 EXPECT_EQ(0u, FindFilenameOffset(""));
44 EXPECT_EQ(0u, FindFilenameOffset("foo"));
45 EXPECT_EQ(4u, FindFilenameOffset("foo/"));
46 EXPECT_EQ(4u, FindFilenameOffset("foo/bar"));
47 }
48
TEST(FilesystemUtils,RemoveFilename)49 TEST(FilesystemUtils, RemoveFilename) {
50 std::string s;
51
52 RemoveFilename(&s);
53 EXPECT_STREQ("", s.c_str());
54
55 s = "foo";
56 RemoveFilename(&s);
57 EXPECT_STREQ("", s.c_str());
58
59 s = "/";
60 RemoveFilename(&s);
61 EXPECT_STREQ("/", s.c_str());
62
63 s = "foo/bar";
64 RemoveFilename(&s);
65 EXPECT_STREQ("foo/", s.c_str());
66
67 s = "foo/bar/baz.cc";
68 RemoveFilename(&s);
69 EXPECT_STREQ("foo/bar/", s.c_str());
70 }
71
TEST(FilesystemUtils,FindDir)72 TEST(FilesystemUtils, FindDir) {
73 std::string input;
74 EXPECT_EQ("", FindDir(&input));
75 input = "/";
76 EXPECT_EQ("/", FindDir(&input));
77 input = "foo/";
78 EXPECT_EQ("foo/", FindDir(&input));
79 input = "foo/bar/baz";
80 EXPECT_EQ("foo/bar/", FindDir(&input));
81 }
82
TEST(FilesystemUtils,FindLastDirComponent)83 TEST(FilesystemUtils, FindLastDirComponent) {
84 SourceDir empty;
85 EXPECT_EQ("", FindLastDirComponent(empty));
86
87 SourceDir root("/");
88 EXPECT_EQ("", FindLastDirComponent(root));
89
90 SourceDir srcroot("//");
91 EXPECT_EQ("", FindLastDirComponent(srcroot));
92
93 SourceDir regular1("//foo/");
94 EXPECT_EQ("foo", FindLastDirComponent(regular1));
95
96 SourceDir regular2("//foo/bar/");
97 EXPECT_EQ("bar", FindLastDirComponent(regular2));
98 }
99
TEST(FilesystemUtils,EnsureStringIsInOutputDir)100 TEST(FilesystemUtils, EnsureStringIsInOutputDir) {
101 SourceDir output_dir("//out/Debug/");
102
103 // Some outside.
104 Err err;
105 EXPECT_FALSE(EnsureStringIsInOutputDir(output_dir, "//foo", nullptr, &err));
106 EXPECT_TRUE(err.has_error());
107 err = Err();
108 EXPECT_FALSE(
109 EnsureStringIsInOutputDir(output_dir, "//out/Debugit", nullptr, &err));
110 EXPECT_TRUE(err.has_error());
111
112 // Some inside.
113 err = Err();
114 EXPECT_TRUE(
115 EnsureStringIsInOutputDir(output_dir, "//out/Debug/", nullptr, &err));
116 EXPECT_FALSE(err.has_error());
117 EXPECT_TRUE(
118 EnsureStringIsInOutputDir(output_dir, "//out/Debug/foo", nullptr, &err));
119 EXPECT_FALSE(err.has_error());
120
121 // Pattern but no template expansions are allowed.
122 EXPECT_FALSE(EnsureStringIsInOutputDir(output_dir, "{{source_gen_dir}}",
123 nullptr, &err));
124 EXPECT_TRUE(err.has_error());
125 }
126
TEST(FilesystemUtils,IsPathAbsolute)127 TEST(FilesystemUtils, IsPathAbsolute) {
128 EXPECT_TRUE(IsPathAbsolute("/foo/bar"));
129 EXPECT_TRUE(IsPathAbsolute("/"));
130 EXPECT_FALSE(IsPathAbsolute(""));
131 EXPECT_FALSE(IsPathAbsolute("//"));
132 EXPECT_FALSE(IsPathAbsolute("//foo/bar"));
133
134 #if defined(OS_WIN)
135 EXPECT_TRUE(IsPathAbsolute("C:/foo"));
136 EXPECT_TRUE(IsPathAbsolute("C:/"));
137 EXPECT_TRUE(IsPathAbsolute("C:\\foo"));
138 EXPECT_TRUE(IsPathAbsolute("C:\\"));
139 EXPECT_TRUE(IsPathAbsolute("/C:/foo"));
140 EXPECT_TRUE(IsPathAbsolute("/C:\\foo"));
141 #endif
142 }
143
TEST(FilesystemUtils,MakeAbsolutePathRelativeIfPossible)144 TEST(FilesystemUtils, MakeAbsolutePathRelativeIfPossible) {
145 std::string dest;
146
147 #if defined(OS_WIN)
148 EXPECT_TRUE(
149 MakeAbsolutePathRelativeIfPossible("C:\\base", "C:\\base\\foo", &dest));
150 EXPECT_EQ("//foo", dest);
151 EXPECT_TRUE(
152 MakeAbsolutePathRelativeIfPossible("C:\\base", "/C:/base/foo", &dest));
153 EXPECT_EQ("//foo", dest);
154 EXPECT_TRUE(
155 MakeAbsolutePathRelativeIfPossible("c:\\base", "C:\\base\\foo\\", &dest));
156 EXPECT_EQ("//foo\\", dest);
157
158 EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("C:\\base", "C:\\ba", &dest));
159 EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("C:\\base",
160 "C:\\/notbase/foo", &dest));
161 #else
162
163 EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo/", &dest));
164 EXPECT_EQ("//foo/", dest);
165 EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo", &dest));
166 EXPECT_EQ("//foo", dest);
167 EXPECT_TRUE(
168 MakeAbsolutePathRelativeIfPossible("/base/", "/base/foo/", &dest));
169 EXPECT_EQ("//foo/", dest);
170
171 EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("/base", "/ba", &dest));
172 EXPECT_FALSE(
173 MakeAbsolutePathRelativeIfPossible("/base", "/notbase/foo", &dest));
174 #endif
175 }
176
TEST(FilesystemUtils,MakeAbsoluteFilePathRelativeIfPossible)177 TEST(FilesystemUtils, MakeAbsoluteFilePathRelativeIfPossible) {
178 #if defined(OS_WIN)
179 EXPECT_EQ(
180 base::FilePath(u"out\\Debug"),
181 MakeAbsoluteFilePathRelativeIfPossible(
182 base::FilePath(u"C:\\src"), base::FilePath(u"C:\\src\\out\\Debug")));
183 EXPECT_EQ(base::FilePath(u".\\gn"),
184 MakeAbsoluteFilePathRelativeIfPossible(
185 base::FilePath(u"C:\\src\\out\\Debug"),
186 base::FilePath(u"C:\\src\\out\\Debug\\gn")));
187 EXPECT_EQ(
188 base::FilePath(u"..\\.."),
189 MakeAbsoluteFilePathRelativeIfPossible(
190 base::FilePath(u"C:\\src\\out\\Debug"), base::FilePath(u"C:\\src")));
191 EXPECT_EQ(
192 base::FilePath(u"..\\.."),
193 MakeAbsoluteFilePathRelativeIfPossible(
194 base::FilePath(u"C:\\src\\out\\Debug"), base::FilePath(u"C:/src")));
195 EXPECT_EQ(base::FilePath(u"."),
196 MakeAbsoluteFilePathRelativeIfPossible(base::FilePath(u"C:\\src"),
197 base::FilePath(u"C:\\src")));
198 EXPECT_EQ(base::FilePath(u"..\\..\\..\\u\\v\\w"),
199 MakeAbsoluteFilePathRelativeIfPossible(
200 base::FilePath(u"C:\\a\\b\\c\\x\\y\\z"),
201 base::FilePath(u"C:\\a\\b\\c\\u\\v\\w")));
202 EXPECT_EQ(base::FilePath(u"D:\\bar"),
203 MakeAbsoluteFilePathRelativeIfPossible(base::FilePath(u"C:\\foo"),
204 base::FilePath(u"D:\\bar")));
205 #else
206 EXPECT_EQ(base::FilePath("out/Debug"),
207 MakeAbsoluteFilePathRelativeIfPossible(
208 base::FilePath("/src"), base::FilePath("/src/out/Debug")));
209 EXPECT_EQ(base::FilePath("./gn"), MakeAbsoluteFilePathRelativeIfPossible(
210 base::FilePath("/src/out/Debug"),
211 base::FilePath("/src/out/Debug/gn")));
212 EXPECT_EQ(base::FilePath("../.."),
213 MakeAbsoluteFilePathRelativeIfPossible(
214 base::FilePath("/src/out/Debug"), base::FilePath("/src")));
215 EXPECT_EQ(base::FilePath("."),
216 MakeAbsoluteFilePathRelativeIfPossible(base::FilePath("/src"),
217 base::FilePath("/src")));
218 EXPECT_EQ(
219 base::FilePath("../../../u/v/w"),
220 MakeAbsoluteFilePathRelativeIfPossible(base::FilePath("/a/b/c/x/y/z"),
221 base::FilePath("/a/b/c/u/v/w")));
222 #endif
223 }
224
TEST(FilesystemUtils,NormalizePath)225 TEST(FilesystemUtils, NormalizePath) {
226 std::string input;
227
228 NormalizePath(&input);
229 EXPECT_EQ("", input);
230
231 input = "foo/bar.txt";
232 NormalizePath(&input);
233 EXPECT_EQ("foo/bar.txt", input);
234
235 input = ".";
236 NormalizePath(&input);
237 EXPECT_EQ("", input);
238
239 input = "..";
240 NormalizePath(&input);
241 EXPECT_EQ("..", input);
242
243 input = "foo//bar";
244 NormalizePath(&input);
245 EXPECT_EQ("foo/bar", input);
246
247 input = "//foo";
248 NormalizePath(&input);
249 EXPECT_EQ("//foo", input);
250
251 input = "foo/..//bar";
252 NormalizePath(&input);
253 EXPECT_EQ("bar", input);
254
255 input = "foo/../../bar";
256 NormalizePath(&input);
257 EXPECT_EQ("../bar", input);
258
259 input = "/../foo"; // Don't go above the root dir.
260 NormalizePath(&input);
261 EXPECT_EQ("/foo", input);
262
263 input = "//../foo"; // Don't go above the root dir.
264 NormalizePath(&input);
265 EXPECT_EQ("//foo", input);
266
267 input = "../foo";
268 NormalizePath(&input);
269 EXPECT_EQ("../foo", input);
270
271 input = "..";
272 NormalizePath(&input);
273 EXPECT_EQ("..", input);
274
275 input = "./././.";
276 NormalizePath(&input);
277 EXPECT_EQ("", input);
278
279 input = "../../..";
280 NormalizePath(&input);
281 EXPECT_EQ("../../..", input);
282
283 input = "../";
284 NormalizePath(&input);
285 EXPECT_EQ("../", input);
286
287 // Backslash normalization.
288 input = "foo\\..\\..\\bar";
289 NormalizePath(&input);
290 EXPECT_EQ("../bar", input);
291
292 // Trailing slashes should get preserved.
293 input = "//foo/bar/";
294 NormalizePath(&input);
295 EXPECT_EQ("//foo/bar/", input);
296
297 #if defined(OS_WIN)
298 // Go above and outside of the source root.
299 input = "//../foo";
300 NormalizePath(&input, "/C:/source/root");
301 EXPECT_EQ("/C:/source/foo", input);
302
303 input = "//../foo";
304 NormalizePath(&input, "C:\\source\\root");
305 EXPECT_EQ("/C:/source/foo", input);
306
307 input = "//../";
308 NormalizePath(&input, "/C:/source/root");
309 EXPECT_EQ("/C:/source/", input);
310
311 input = "//../foo.txt";
312 NormalizePath(&input, "/C:/source/root");
313 EXPECT_EQ("/C:/source/foo.txt", input);
314
315 input = "//../foo/bar/";
316 NormalizePath(&input, "/C:/source/root");
317 EXPECT_EQ("/C:/source/foo/bar/", input);
318
319 // Go above and back into the source root. This should return a system-
320 // absolute path. We could arguably return this as a source-absolute path,
321 // but that would require additional handling to account for a rare edge
322 // case.
323 input = "//../root/foo";
324 NormalizePath(&input, "/C:/source/root");
325 EXPECT_EQ("/C:/source/root/foo", input);
326
327 input = "//../root/foo/bar/";
328 NormalizePath(&input, "/C:/source/root");
329 EXPECT_EQ("/C:/source/root/foo/bar/", input);
330
331 // Stay inside the source root
332 input = "//foo/bar";
333 NormalizePath(&input, "/C:/source/root");
334 EXPECT_EQ("//foo/bar", input);
335
336 input = "//foo/bar/";
337 NormalizePath(&input, "/C:/source/root");
338 EXPECT_EQ("//foo/bar/", input);
339
340 // The path should not go above the system root. Note that on Windows, this
341 // will consume the drive (C:).
342 input = "//../../../../../foo/bar";
343 NormalizePath(&input, "/C:/source/root");
344 EXPECT_EQ("/foo/bar", input);
345
346 // Test when the source root is the letter drive.
347 input = "//../foo";
348 NormalizePath(&input, "/C:");
349 EXPECT_EQ("/foo", input);
350
351 input = "//../foo";
352 NormalizePath(&input, "C:");
353 EXPECT_EQ("/foo", input);
354
355 input = "//../foo";
356 NormalizePath(&input, "/");
357 EXPECT_EQ("/foo", input);
358
359 input = "//../";
360 NormalizePath(&input, "\\C:");
361 EXPECT_EQ("/", input);
362
363 input = "//../foo.txt";
364 NormalizePath(&input, "/C:");
365 EXPECT_EQ("/foo.txt", input);
366 #else
367 // Go above and outside of the source root.
368 input = "//../foo";
369 NormalizePath(&input, "/source/root");
370 EXPECT_EQ("/source/foo", input);
371
372 input = "//../";
373 NormalizePath(&input, "/source/root");
374 EXPECT_EQ("/source/", input);
375
376 input = "//../foo.txt";
377 NormalizePath(&input, "/source/root");
378 EXPECT_EQ("/source/foo.txt", input);
379
380 input = "//../foo/bar/";
381 NormalizePath(&input, "/source/root");
382 EXPECT_EQ("/source/foo/bar/", input);
383
384 // Go above and back into the source root. This should return a system-
385 // absolute path. We could arguably return this as a source-absolute path,
386 // but that would require additional handling to account for a rare edge
387 // case.
388 input = "//../root/foo";
389 NormalizePath(&input, "/source/root");
390 EXPECT_EQ("/source/root/foo", input);
391
392 input = "//../root/foo/bar/";
393 NormalizePath(&input, "/source/root");
394 EXPECT_EQ("/source/root/foo/bar/", input);
395
396 // Stay inside the source root
397 input = "//foo/bar";
398 NormalizePath(&input, "/source/root");
399 EXPECT_EQ("//foo/bar", input);
400
401 input = "//foo/bar/";
402 NormalizePath(&input, "/source/root");
403 EXPECT_EQ("//foo/bar/", input);
404
405 // The path should not go above the system root.
406 input = "//../../../../../foo/bar";
407 NormalizePath(&input, "/source/root");
408 EXPECT_EQ("/foo/bar", input);
409
410 // Test when the source root is the system root.
411 input = "//../foo/bar/";
412 NormalizePath(&input, "/");
413 EXPECT_EQ("/foo/bar/", input);
414
415 input = "//../";
416 NormalizePath(&input, "/");
417 EXPECT_EQ("/", input);
418
419 input = "//../foo.txt";
420 NormalizePath(&input, "/");
421 EXPECT_EQ("/foo.txt", input);
422
423 #endif
424 }
425
TEST(FilesystemUtils,RebasePath)426 TEST(FilesystemUtils, RebasePath) {
427 std::string_view source_root("/source/root");
428
429 // Degenerate case.
430 EXPECT_EQ(".", RebasePath("//", SourceDir("//"), source_root));
431 EXPECT_EQ(".",
432 RebasePath("//foo/bar/", SourceDir("//foo/bar/"), source_root));
433
434 // Going up the tree.
435 EXPECT_EQ("../foo", RebasePath("//foo", SourceDir("//bar/"), source_root));
436 EXPECT_EQ("../foo/", RebasePath("//foo/", SourceDir("//bar/"), source_root));
437 EXPECT_EQ("../../foo",
438 RebasePath("//foo", SourceDir("//bar/moo"), source_root));
439 EXPECT_EQ("../../foo/",
440 RebasePath("//foo/", SourceDir("//bar/moo"), source_root));
441
442 // Going down the tree.
443 EXPECT_EQ("foo/bar", RebasePath("//foo/bar", SourceDir("//"), source_root));
444 EXPECT_EQ("foo/bar/", RebasePath("//foo/bar/", SourceDir("//"), source_root));
445
446 // Going up and down the tree.
447 EXPECT_EQ("../../foo/bar",
448 RebasePath("//foo/bar", SourceDir("//a/b/"), source_root));
449 EXPECT_EQ("../../foo/bar/",
450 RebasePath("//foo/bar/", SourceDir("//a/b/"), source_root));
451
452 // Sharing prefix.
453 EXPECT_EQ("foo", RebasePath("//a/foo", SourceDir("//a/"), source_root));
454 EXPECT_EQ("foo", RebasePath("//a/foo", SourceDir("//a"), source_root));
455 EXPECT_EQ("foo/", RebasePath("//a/foo/", SourceDir("//a/"), source_root));
456 EXPECT_EQ("foo", RebasePath("//a/b/foo", SourceDir("//a/b/"), source_root));
457 EXPECT_EQ("foo/", RebasePath("//a/b/foo/", SourceDir("//a/b/"), source_root));
458 EXPECT_EQ("foo/bar",
459 RebasePath("//a/b/foo/bar", SourceDir("//a/b/"), source_root));
460 EXPECT_EQ("foo/bar/",
461 RebasePath("//a/b/foo/bar/", SourceDir("//a/b/"), source_root));
462 EXPECT_EQ(".", RebasePath("//foo/bar", SourceDir("//foo/bar/"), source_root));
463 EXPECT_EQ("..", RebasePath("//foo", SourceDir("//foo/bar/"), source_root));
464 EXPECT_EQ("../", RebasePath("//foo/", SourceDir("//foo/bar/"), source_root));
465
466 // Check when only |input| is system-absolute
467 EXPECT_EQ("foo", RebasePath("/source/root/foo", SourceDir("//"),
468 std::string_view("/source/root")));
469 EXPECT_EQ("foo/", RebasePath("/source/root/foo/", SourceDir("//"),
470 std::string_view("/source/root")));
471 EXPECT_EQ("../../builddir/Out/Debug",
472 RebasePath("/builddir/Out/Debug", SourceDir("//"),
473 std::string_view("/source/root")));
474 EXPECT_EQ("../../../builddir/Out/Debug",
475 RebasePath("/builddir/Out/Debug", SourceDir("//"),
476 std::string_view("/source/root/foo")));
477 EXPECT_EQ("../../../builddir/Out/Debug/",
478 RebasePath("/builddir/Out/Debug/", SourceDir("//"),
479 std::string_view("/source/root/foo")));
480 EXPECT_EQ("../../path/to/foo", RebasePath("/path/to/foo", SourceDir("//"),
481 std::string_view("/source/root")));
482 EXPECT_EQ("../../../path/to/foo",
483 RebasePath("/path/to/foo", SourceDir("//a"),
484 std::string_view("/source/root")));
485 EXPECT_EQ("../../../../path/to/foo",
486 RebasePath("/path/to/foo", SourceDir("//a/b"),
487 std::string_view("/source/root")));
488
489 // Check when only |dest_dir| is system-absolute.
490 EXPECT_EQ(".", RebasePath("//", SourceDir("/source/root"),
491 std::string_view("/source/root")));
492 EXPECT_EQ("foo", RebasePath("//foo", SourceDir("/source/root"),
493 std::string_view("/source/root")));
494 EXPECT_EQ("../foo", RebasePath("//foo", SourceDir("/source/root/bar"),
495 std::string_view("/source/root")));
496 EXPECT_EQ("../../../source/root/foo",
497 RebasePath("//foo", SourceDir("/other/source/root"),
498 std::string_view("/source/root")));
499 EXPECT_EQ("../../../../source/root/foo",
500 RebasePath("//foo", SourceDir("/other/source/root/bar"),
501 std::string_view("/source/root")));
502
503 // Check when |input| and |dest_dir| are both system-absolute. Also,
504 // in this case |source_root| is never used so set it to a dummy
505 // value.
506 EXPECT_EQ("foo", RebasePath("/source/root/foo", SourceDir("/source/root"),
507 std::string_view("/x/y/z")));
508 EXPECT_EQ("foo/", RebasePath("/source/root/foo/", SourceDir("/source/root"),
509 std::string_view("/x/y/z")));
510 EXPECT_EQ("../../builddir/Out/Debug",
511 RebasePath("/builddir/Out/Debug", SourceDir("/source/root"),
512 std::string_view("/x/y/z")));
513 EXPECT_EQ("../../../builddir/Out/Debug",
514 RebasePath("/builddir/Out/Debug", SourceDir("/source/root/foo"),
515 std::string_view("/source/root/foo")));
516 EXPECT_EQ("../../../builddir/Out/Debug/",
517 RebasePath("/builddir/Out/Debug/", SourceDir("/source/root/foo"),
518 std::string_view("/source/root/foo")));
519 EXPECT_EQ("../../path/to/foo",
520 RebasePath("/path/to/foo", SourceDir("/source/root"),
521 std::string_view("/x/y/z")));
522 EXPECT_EQ("../../../path/to/foo",
523 RebasePath("/path/to/foo", SourceDir("/source/root/a"),
524 std::string_view("/x/y/z")));
525 EXPECT_EQ("../../../../path/to/foo",
526 RebasePath("/path/to/foo", SourceDir("/source/root/a/b"),
527 std::string_view("/x/y/z")));
528
529 #if defined(OS_WIN)
530 // Test corrections while rebasing Windows-style absolute paths.
531 EXPECT_EQ("../../../../path/to/foo",
532 RebasePath("C:/path/to/foo", SourceDir("//a/b"),
533 std::string_view("/C:/source/root")));
534 EXPECT_EQ("../../../../path/to/foo",
535 RebasePath("/C:/path/to/foo", SourceDir("//a/b"),
536 std::string_view("C:/source/root")));
537 EXPECT_EQ("../../../../path/to/foo",
538 RebasePath("/C:/path/to/foo", SourceDir("//a/b"),
539 std::string_view("/c:/source/root")));
540 EXPECT_EQ("../../../../path/to/foo",
541 RebasePath("/c:/path/to/foo", SourceDir("//a/b"),
542 std::string_view("c:/source/root")));
543 EXPECT_EQ("../../../../path/to/foo",
544 RebasePath("/c:/path/to/foo", SourceDir("//a/b"),
545 std::string_view("C:/source/root")));
546
547 // Should be absolute path of destination if the drive letters are
548 // different between two paths.
549 EXPECT_EQ("C:/path/to/foo",
550 RebasePath("C:/path/to/foo", SourceDir("//a/b"),
551 std::string_view("D:/source/root")));
552 EXPECT_EQ("D:/path/to/foo",
553 RebasePath("D:/path/to/foo", SourceDir("//a/b"),
554 std::string_view("C:/source/root")));
555 EXPECT_EQ("E:/path/to/foo",
556 RebasePath("/E:/path/to/foo", SourceDir("//a/b"),
557 std::string_view("/c:/source/root")));
558 EXPECT_EQ("E:/path/to/foo",
559 RebasePath("/e:/path/to/foo", SourceDir("//a/b"),
560 std::string_view("c:/source/root")));
561 EXPECT_EQ("C:/path/to/foo",
562 RebasePath("/c:/path/to/foo", SourceDir("//a/b"),
563 std::string_view("D:/source/root")));
564 #endif
565 }
566
TEST(FilesystemUtils,DirectoryWithNoLastSlash)567 TEST(FilesystemUtils, DirectoryWithNoLastSlash) {
568 EXPECT_EQ("", DirectoryWithNoLastSlash(SourceDir()));
569 EXPECT_EQ("/.", DirectoryWithNoLastSlash(SourceDir("/")));
570 EXPECT_EQ("//.", DirectoryWithNoLastSlash(SourceDir("//")));
571 EXPECT_EQ("//foo", DirectoryWithNoLastSlash(SourceDir("//foo/")));
572 EXPECT_EQ("/bar", DirectoryWithNoLastSlash(SourceDir("/bar/")));
573 }
574
TEST(FilesystemUtils,SourceDirForPath)575 TEST(FilesystemUtils, SourceDirForPath) {
576 #if defined(OS_WIN)
577 base::FilePath root(u"C:\\source\\foo\\");
578 EXPECT_EQ("/C:/foo/bar/",
579 SourceDirForPath(root, base::FilePath(u"C:\\foo\\bar")).value());
580 EXPECT_EQ("/", SourceDirForPath(root, base::FilePath(u"/")).value());
581 EXPECT_EQ("//",
582 SourceDirForPath(root, base::FilePath(u"C:\\source\\foo")).value());
583 EXPECT_EQ("//bar/",
584 SourceDirForPath(root, base::FilePath(u"C:\\source\\foo\\bar\\"))
585 .value());
586 EXPECT_EQ("//bar/baz/",
587 SourceDirForPath(root, base::FilePath(u"C:\\source\\foo\\bar\\baz"))
588 .value());
589
590 // Should be case-and-slash-insensitive.
591 EXPECT_EQ(
592 "//baR/",
593 SourceDirForPath(root, base::FilePath(u"c:/SOURCE\\Foo/baR/")).value());
594
595 // Some "weird" Windows paths.
596 EXPECT_EQ("/foo/bar/",
597 SourceDirForPath(root, base::FilePath(u"/foo/bar/")).value());
598 EXPECT_EQ("/C:/foo/bar/",
599 SourceDirForPath(root, base::FilePath(u"C:foo/bar/")).value());
600
601 // Also allow absolute GN-style Windows paths.
602 EXPECT_EQ("/C:/foo/bar/",
603 SourceDirForPath(root, base::FilePath(u"/C:/foo/bar")).value());
604 EXPECT_EQ(
605 "//bar/",
606 SourceDirForPath(root, base::FilePath(u"/C:/source/foo/bar")).value());
607
608 // Empty source dir.
609 base::FilePath empty;
610 EXPECT_EQ(
611 "/C:/source/foo/",
612 SourceDirForPath(empty, base::FilePath(u"C:\\source\\foo")).value());
613 #else
614 base::FilePath root("/source/foo/");
615 EXPECT_EQ("/foo/bar/",
616 SourceDirForPath(root, base::FilePath("/foo/bar/")).value());
617 EXPECT_EQ("/", SourceDirForPath(root, base::FilePath("/")).value());
618 EXPECT_EQ("//",
619 SourceDirForPath(root, base::FilePath("/source/foo")).value());
620 EXPECT_EQ("//bar/",
621 SourceDirForPath(root, base::FilePath("/source/foo/bar/")).value());
622 EXPECT_EQ(
623 "//bar/baz/",
624 SourceDirForPath(root, base::FilePath("/source/foo/bar/baz/")).value());
625
626 // Should be case-sensitive.
627 EXPECT_EQ("/SOURCE/foo/bar/",
628 SourceDirForPath(root, base::FilePath("/SOURCE/foo/bar/")).value());
629
630 // Empty source dir.
631 base::FilePath empty;
632 EXPECT_EQ("/source/foo/",
633 SourceDirForPath(empty, base::FilePath("/source/foo")).value());
634 #endif
635 }
636
TEST(FilesystemUtils,ContentsEqual)637 TEST(FilesystemUtils, ContentsEqual) {
638 base::ScopedTempDir temp_dir;
639 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
640
641 std::string data = "foo";
642
643 base::FilePath file_path = temp_dir.GetPath().AppendASCII("foo.txt");
644 base::WriteFile(file_path, data.c_str(), static_cast<int>(data.size()));
645
646 EXPECT_TRUE(ContentsEqual(file_path, data));
647
648 // Different length and contents.
649 data += "bar";
650 EXPECT_FALSE(ContentsEqual(file_path, data));
651
652 // The same length, different contents.
653 EXPECT_FALSE(ContentsEqual(file_path, "bar"));
654 }
655
TEST(FilesystemUtils,GetToolchainDirs)656 TEST(FilesystemUtils, GetToolchainDirs) {
657 BuildSettings build_settings;
658 build_settings.SetBuildDir(SourceDir("//out/Debug/"));
659
660 // The default toolchain.
661 Settings default_settings(&build_settings, "");
662 Label default_toolchain_label(SourceDir("//toolchain/"), "default");
663 default_settings.set_toolchain_label(default_toolchain_label);
664 default_settings.set_default_toolchain_label(default_toolchain_label);
665 BuildDirContext default_context(&default_settings);
666
667 // Default toolchain out dir as source dirs.
668 EXPECT_EQ("//out/Debug/", GetBuildDirAsSourceDir(default_context,
669 BuildDirType::TOOLCHAIN_ROOT)
670 .value());
671 EXPECT_EQ("//out/Debug/obj/",
672 GetBuildDirAsSourceDir(default_context, BuildDirType::OBJ).value());
673 EXPECT_EQ("//out/Debug/gen/",
674 GetBuildDirAsSourceDir(default_context, BuildDirType::GEN).value());
675
676 // Default toolchain our dir as output files.
677 EXPECT_EQ(
678 "", GetBuildDirAsOutputFile(default_context, BuildDirType::TOOLCHAIN_ROOT)
679 .value());
680 EXPECT_EQ(
681 "obj/",
682 GetBuildDirAsOutputFile(default_context, BuildDirType::OBJ).value());
683 EXPECT_EQ(
684 "gen/",
685 GetBuildDirAsOutputFile(default_context, BuildDirType::GEN).value());
686
687 // Check a secondary toolchain.
688 Settings other_settings(&build_settings, "two/");
689 Label other_toolchain_label(SourceDir("//toolchain/"), "two");
690 other_settings.set_toolchain_label(other_toolchain_label);
691 other_settings.set_default_toolchain_label(default_toolchain_label);
692 BuildDirContext other_context(&other_settings);
693
694 // Secondary toolchain out dir as source dirs.
695 EXPECT_EQ("//out/Debug/two/",
696 GetBuildDirAsSourceDir(other_context, BuildDirType::TOOLCHAIN_ROOT)
697 .value());
698 EXPECT_EQ("//out/Debug/two/obj/",
699 GetBuildDirAsSourceDir(other_context, BuildDirType::OBJ).value());
700 EXPECT_EQ("//out/Debug/two/gen/",
701 GetBuildDirAsSourceDir(other_context, BuildDirType::GEN).value());
702
703 // Secondary toolchain out dir as output files.
704 EXPECT_EQ("two/",
705 GetBuildDirAsOutputFile(other_context, BuildDirType::TOOLCHAIN_ROOT)
706 .value());
707 EXPECT_EQ("two/obj/",
708 GetBuildDirAsOutputFile(other_context, BuildDirType::OBJ).value());
709 EXPECT_EQ("two/gen/",
710 GetBuildDirAsOutputFile(other_context, BuildDirType::GEN).value());
711 }
712
TEST(FilesystemUtils,GetSubBuildDir)713 TEST(FilesystemUtils, GetSubBuildDir) {
714 BuildSettings build_settings;
715 build_settings.SetBuildDir(SourceDir("//out/Debug/"));
716
717 // Test the default toolchain.
718 Label default_toolchain_label(SourceDir("//toolchain/"), "default");
719 Settings default_settings(&build_settings, "");
720 default_settings.set_toolchain_label(default_toolchain_label);
721 default_settings.set_default_toolchain_label(default_toolchain_label);
722 BuildDirContext default_context(&default_settings);
723
724 // Target in the root.
725 EXPECT_EQ("//out/Debug/obj/",
726 GetSubBuildDirAsSourceDir(default_context, SourceDir("//"),
727 BuildDirType::OBJ)
728 .value());
729 EXPECT_EQ("gen/", GetSubBuildDirAsOutputFile(default_context, SourceDir("//"),
730 BuildDirType::GEN)
731 .value());
732
733 // Target in another directory.
734 EXPECT_EQ("//out/Debug/obj/foo/bar/",
735 GetSubBuildDirAsSourceDir(default_context, SourceDir("//foo/bar/"),
736 BuildDirType::OBJ)
737 .value());
738 EXPECT_EQ("gen/foo/bar/",
739 GetSubBuildDirAsOutputFile(default_context, SourceDir("//foo/bar/"),
740 BuildDirType::GEN)
741 .value());
742
743 // Secondary toolchain.
744 Settings other_settings(&build_settings, "two/");
745 other_settings.set_toolchain_label(Label(SourceDir("//toolchain/"), "two"));
746 other_settings.set_default_toolchain_label(default_toolchain_label);
747 BuildDirContext other_context(&other_settings);
748
749 // Target in the root.
750 EXPECT_EQ("//out/Debug/two/obj/",
751 GetSubBuildDirAsSourceDir(other_context, SourceDir("//"),
752 BuildDirType::OBJ)
753 .value());
754 EXPECT_EQ("two/gen/", GetSubBuildDirAsOutputFile(
755 other_context, SourceDir("//"), BuildDirType::GEN)
756 .value());
757
758 // Target in another directory.
759 EXPECT_EQ("//out/Debug/two/obj/foo/bar/",
760 GetSubBuildDirAsSourceDir(other_context, SourceDir("//foo/bar/"),
761 BuildDirType::OBJ)
762 .value());
763 EXPECT_EQ("two/gen/foo/bar/",
764 GetSubBuildDirAsOutputFile(other_context, SourceDir("//foo/bar/"),
765 BuildDirType::GEN)
766 .value());
767
768 // Absolute source path
769 EXPECT_EQ("//out/Debug/obj/ABS_PATH/abs/",
770 GetSubBuildDirAsSourceDir(default_context, SourceDir("/abs"),
771 BuildDirType::OBJ)
772 .value());
773 EXPECT_EQ("gen/ABS_PATH/abs/",
774 GetSubBuildDirAsOutputFile(default_context, SourceDir("/abs"),
775 BuildDirType::GEN)
776 .value());
777 #if defined(OS_WIN)
778 EXPECT_EQ("//out/Debug/obj/ABS_PATH/C/abs/",
779 GetSubBuildDirAsSourceDir(default_context, SourceDir("/C:/abs"),
780 BuildDirType::OBJ)
781 .value());
782 EXPECT_EQ("gen/ABS_PATH/C/abs/",
783 GetSubBuildDirAsOutputFile(default_context, SourceDir("/C:/abs"),
784 BuildDirType::GEN)
785 .value());
786 #endif
787 }
788
TEST(FilesystemUtils,GetBuildDirForTarget)789 TEST(FilesystemUtils, GetBuildDirForTarget) {
790 BuildSettings build_settings;
791 build_settings.SetBuildDir(SourceDir("//out/Debug/"));
792 Settings settings(&build_settings, "");
793
794 Target a(&settings, Label(SourceDir("//foo/bar/"), "baz"));
795 EXPECT_EQ("//out/Debug/obj/foo/bar/",
796 GetBuildDirForTargetAsSourceDir(&a, BuildDirType::OBJ).value());
797 EXPECT_EQ("obj/foo/bar/",
798 GetBuildDirForTargetAsOutputFile(&a, BuildDirType::OBJ).value());
799 EXPECT_EQ("//out/Debug/gen/foo/bar/",
800 GetBuildDirForTargetAsSourceDir(&a, BuildDirType::GEN).value());
801 EXPECT_EQ("gen/foo/bar/",
802 GetBuildDirForTargetAsOutputFile(&a, BuildDirType::GEN).value());
803 }
804
805 // Tests handling of output dirs when build dir is the same as the root.
TEST(FilesystemUtils,GetDirForEmptyBuildDir)806 TEST(FilesystemUtils, GetDirForEmptyBuildDir) {
807 BuildSettings build_settings;
808 build_settings.SetBuildDir(SourceDir("//"));
809 Settings settings(&build_settings, "");
810
811 BuildDirContext context(&settings);
812
813 EXPECT_EQ(
814 "//",
815 GetBuildDirAsSourceDir(context, BuildDirType::TOOLCHAIN_ROOT).value());
816 EXPECT_EQ("//gen/",
817 GetBuildDirAsSourceDir(context, BuildDirType::GEN).value());
818 EXPECT_EQ("//obj/",
819 GetBuildDirAsSourceDir(context, BuildDirType::OBJ).value());
820
821 EXPECT_EQ(
822 "",
823 GetBuildDirAsOutputFile(context, BuildDirType::TOOLCHAIN_ROOT).value());
824 EXPECT_EQ("gen/",
825 GetBuildDirAsOutputFile(context, BuildDirType::GEN).value());
826 EXPECT_EQ("obj/",
827 GetBuildDirAsOutputFile(context, BuildDirType::OBJ).value());
828 }
829
TEST(FilesystemUtils,ResolveRelativeTest)830 TEST(FilesystemUtils, ResolveRelativeTest) {
831 std::string result;
832 #ifndef OS_WIN
833 EXPECT_TRUE(
834 MakeAbsolutePathRelativeIfPossible("/some/dir", "/some/dir/a", &result));
835 EXPECT_EQ(result, "//a");
836
837 EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible(
838 "/some/dir", "/some/dir-sufix/a", &result));
839 #else
840 EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("C:/some/dir",
841 "/C:/some/dir/a", &result));
842 EXPECT_EQ(result, "//a");
843 EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible(
844 "C:/some/dir", "C:/some/dir-sufix/a", &result));
845 #endif
846 }
847