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 "base/strings/string_util.h"
6#include "base/strings/utf_string_conversions.h"
7#include "build/build_config.h"
8#include "testing/gtest/include/gtest/gtest.h"
9#include "tools/gn/filesystem_utils.h"
10#include "tools/gn/target.h"
11
12TEST(FilesystemUtils, FileExtensionOffset) {
13  EXPECT_EQ(std::string::npos, FindExtensionOffset(""));
14  EXPECT_EQ(std::string::npos, FindExtensionOffset("foo/bar/baz"));
15  EXPECT_EQ(4u, FindExtensionOffset("foo."));
16  EXPECT_EQ(4u, FindExtensionOffset("f.o.bar"));
17  EXPECT_EQ(std::string::npos, FindExtensionOffset("foo.bar/"));
18  EXPECT_EQ(std::string::npos, FindExtensionOffset("foo.bar/baz"));
19}
20
21TEST(FilesystemUtils, FindExtension) {
22  std::string input;
23  EXPECT_EQ("", FindExtension(&input).as_string());
24  input = "foo/bar/baz";
25  EXPECT_EQ("", FindExtension(&input).as_string());
26  input = "foo.";
27  EXPECT_EQ("", FindExtension(&input).as_string());
28  input = "f.o.bar";
29  EXPECT_EQ("bar", FindExtension(&input).as_string());
30  input = "foo.bar/";
31  EXPECT_EQ("", FindExtension(&input).as_string());
32  input = "foo.bar/baz";
33  EXPECT_EQ("", FindExtension(&input).as_string());
34}
35
36TEST(FilesystemUtils, FindFilenameOffset) {
37  EXPECT_EQ(0u, FindFilenameOffset(""));
38  EXPECT_EQ(0u, FindFilenameOffset("foo"));
39  EXPECT_EQ(4u, FindFilenameOffset("foo/"));
40  EXPECT_EQ(4u, FindFilenameOffset("foo/bar"));
41}
42
43TEST(FilesystemUtils, RemoveFilename) {
44  std::string s;
45
46  RemoveFilename(&s);
47  EXPECT_STREQ("", s.c_str());
48
49  s = "foo";
50  RemoveFilename(&s);
51  EXPECT_STREQ("", s.c_str());
52
53  s = "/";
54  RemoveFilename(&s);
55  EXPECT_STREQ("/", s.c_str());
56
57  s = "foo/bar";
58  RemoveFilename(&s);
59  EXPECT_STREQ("foo/", s.c_str());
60
61  s = "foo/bar/baz.cc";
62  RemoveFilename(&s);
63  EXPECT_STREQ("foo/bar/", s.c_str());
64}
65
66TEST(FilesystemUtils, FindDir) {
67  std::string input;
68  EXPECT_EQ("", FindDir(&input));
69  input = "/";
70  EXPECT_EQ("/", FindDir(&input));
71  input = "foo/";
72  EXPECT_EQ("foo/", FindDir(&input));
73  input = "foo/bar/baz";
74  EXPECT_EQ("foo/bar/", FindDir(&input));
75}
76
77TEST(FilesystemUtils, FindLastDirComponent) {
78  SourceDir empty;
79  EXPECT_EQ("", FindLastDirComponent(empty));
80
81  SourceDir root("/");
82  EXPECT_EQ("", FindLastDirComponent(root));
83
84  SourceDir srcroot("//");
85  EXPECT_EQ("", FindLastDirComponent(srcroot));
86
87  SourceDir regular1("//foo/");
88  EXPECT_EQ("foo", FindLastDirComponent(regular1));
89
90  SourceDir regular2("//foo/bar/");
91  EXPECT_EQ("bar", FindLastDirComponent(regular2));
92}
93
94TEST(FilesystemUtils, EnsureStringIsInOutputDir) {
95  SourceDir output_dir("//out/Debug/");
96
97  // Some outside.
98  Err err;
99  EXPECT_FALSE(EnsureStringIsInOutputDir(output_dir, "//foo", NULL, &err));
100  EXPECT_TRUE(err.has_error());
101  err = Err();
102  EXPECT_FALSE(EnsureStringIsInOutputDir(output_dir, "//out/Debugit", NULL,
103                                         &err));
104  EXPECT_TRUE(err.has_error());
105
106  // Some inside.
107  err = Err();
108  EXPECT_TRUE(EnsureStringIsInOutputDir(output_dir, "//out/Debug/", NULL,
109                                        &err));
110  EXPECT_FALSE(err.has_error());
111  EXPECT_TRUE(EnsureStringIsInOutputDir(output_dir, "//out/Debug/foo", NULL,
112                                        &err));
113  EXPECT_FALSE(err.has_error());
114
115  // Pattern but no template expansions are allowed.
116  EXPECT_FALSE(EnsureStringIsInOutputDir(output_dir, "{{source_gen_dir}}",
117                                         NULL, &err));
118  EXPECT_TRUE(err.has_error());
119}
120
121TEST(FilesystemUtils, IsPathAbsolute) {
122  EXPECT_TRUE(IsPathAbsolute("/foo/bar"));
123  EXPECT_TRUE(IsPathAbsolute("/"));
124  EXPECT_FALSE(IsPathAbsolute(""));
125  EXPECT_FALSE(IsPathAbsolute("//"));
126  EXPECT_FALSE(IsPathAbsolute("//foo/bar"));
127
128#if defined(OS_WIN)
129  EXPECT_TRUE(IsPathAbsolute("C:/foo"));
130  EXPECT_TRUE(IsPathAbsolute("C:/"));
131  EXPECT_TRUE(IsPathAbsolute("C:\\foo"));
132  EXPECT_TRUE(IsPathAbsolute("C:\\"));
133  EXPECT_TRUE(IsPathAbsolute("/C:/foo"));
134  EXPECT_TRUE(IsPathAbsolute("/C:\\foo"));
135#endif
136}
137
138TEST(FilesystemUtils, MakeAbsolutePathRelativeIfPossible) {
139  std::string dest;
140
141#if defined(OS_WIN)
142  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("C:\\base", "C:\\base\\foo",
143                                                 &dest));
144  EXPECT_EQ("//foo", dest);
145  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("C:\\base", "/C:/base/foo",
146                                                 &dest));
147  EXPECT_EQ("//foo", dest);
148  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("c:\\base", "C:\\base\\foo\\",
149                                                 &dest));
150  EXPECT_EQ("//foo\\", dest);
151
152  EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("C:\\base", "C:\\ba", &dest));
153  EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("C:\\base",
154                                                  "C:\\/notbase/foo",
155                                                  &dest));
156#else
157
158  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo/", &dest));
159  EXPECT_EQ("//foo/", dest);
160  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo", &dest));
161  EXPECT_EQ("//foo", dest);
162  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base/", "/base/foo/",
163                                                 &dest));
164  EXPECT_EQ("//foo/", dest);
165
166  EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("/base", "/ba", &dest));
167  EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("/base", "/notbase/foo",
168                                                  &dest));
169#endif
170}
171
172TEST(FilesystemUtils, InvertDir) {
173  EXPECT_TRUE(InvertDir(SourceDir()) == "");
174  EXPECT_TRUE(InvertDir(SourceDir("/")) == "");
175  EXPECT_TRUE(InvertDir(SourceDir("//")) == "");
176
177  EXPECT_TRUE(InvertDir(SourceDir("//foo/bar")) == "../../");
178  EXPECT_TRUE(InvertDir(SourceDir("//foo\\bar")) == "../../");
179  EXPECT_TRUE(InvertDir(SourceDir("/foo/bar/")) == "../../");
180}
181
182TEST(FilesystemUtils, NormalizePath) {
183  std::string input;
184
185  NormalizePath(&input);
186  EXPECT_EQ("", input);
187
188  input = "foo/bar.txt";
189  NormalizePath(&input);
190  EXPECT_EQ("foo/bar.txt", input);
191
192  input = ".";
193  NormalizePath(&input);
194  EXPECT_EQ("", input);
195
196  input = "..";
197  NormalizePath(&input);
198  EXPECT_EQ("..", input);
199
200  input = "foo//bar";
201  NormalizePath(&input);
202  EXPECT_EQ("foo/bar", input);
203
204  input = "//foo";
205  NormalizePath(&input);
206  EXPECT_EQ("//foo", input);
207
208  input = "foo/..//bar";
209  NormalizePath(&input);
210  EXPECT_EQ("bar", input);
211
212  input = "foo/../../bar";
213  NormalizePath(&input);
214  EXPECT_EQ("../bar", input);
215
216  input = "/../foo";  // Don't go aboe the root dir.
217  NormalizePath(&input);
218  EXPECT_EQ("/foo", input);
219
220  input = "//../foo";  // Don't go above the root dir.
221  NormalizePath(&input);
222  EXPECT_EQ("//foo", input);
223
224  input = "../foo";
225  NormalizePath(&input);
226  EXPECT_EQ("../foo", input);
227
228  input = "..";
229  NormalizePath(&input);
230  EXPECT_EQ("..", input);
231
232  input = "./././.";
233  NormalizePath(&input);
234  EXPECT_EQ("", input);
235
236  input = "../../..";
237  NormalizePath(&input);
238  EXPECT_EQ("../../..", input);
239
240  input = "../";
241  NormalizePath(&input);
242  EXPECT_EQ("../", input);
243
244  // Backslash normalization.
245  input = "foo\\..\\..\\bar";
246  NormalizePath(&input);
247  EXPECT_EQ("../bar", input);
248}
249
250TEST(FilesystemUtils, RebaseSourceAbsolutePath) {
251  // Degenerate case.
252  EXPECT_EQ(".", RebaseSourceAbsolutePath("//", SourceDir("//")));
253  EXPECT_EQ(".",
254            RebaseSourceAbsolutePath("//foo/bar/", SourceDir("//foo/bar/")));
255
256  // Going up the tree.
257  EXPECT_EQ("../foo",
258            RebaseSourceAbsolutePath("//foo", SourceDir("//bar/")));
259  EXPECT_EQ("../foo/",
260            RebaseSourceAbsolutePath("//foo/", SourceDir("//bar/")));
261  EXPECT_EQ("../../foo",
262            RebaseSourceAbsolutePath("//foo", SourceDir("//bar/moo")));
263  EXPECT_EQ("../../foo/",
264            RebaseSourceAbsolutePath("//foo/", SourceDir("//bar/moo")));
265
266  // Going down the tree.
267  EXPECT_EQ("foo/bar",
268            RebaseSourceAbsolutePath("//foo/bar", SourceDir("//")));
269  EXPECT_EQ("foo/bar/",
270            RebaseSourceAbsolutePath("//foo/bar/", SourceDir("//")));
271
272  // Going up and down the tree.
273  EXPECT_EQ("../../foo/bar",
274            RebaseSourceAbsolutePath("//foo/bar", SourceDir("//a/b/")));
275  EXPECT_EQ("../../foo/bar/",
276            RebaseSourceAbsolutePath("//foo/bar/", SourceDir("//a/b/")));
277
278  // Sharing prefix.
279  EXPECT_EQ("foo",
280            RebaseSourceAbsolutePath("//a/foo", SourceDir("//a/")));
281  EXPECT_EQ("foo/",
282            RebaseSourceAbsolutePath("//a/foo/", SourceDir("//a/")));
283  EXPECT_EQ("foo",
284            RebaseSourceAbsolutePath("//a/b/foo", SourceDir("//a/b/")));
285  EXPECT_EQ("foo/",
286            RebaseSourceAbsolutePath("//a/b/foo/", SourceDir("//a/b/")));
287  EXPECT_EQ("foo/bar",
288            RebaseSourceAbsolutePath("//a/b/foo/bar", SourceDir("//a/b/")));
289  EXPECT_EQ("foo/bar/",
290            RebaseSourceAbsolutePath("//a/b/foo/bar/", SourceDir("//a/b/")));
291
292  // One could argue about this case. Since the input doesn't have a slash it
293  // would normally not be treated like a directory and we'd go up, which is
294  // simpler. However, since it matches the output directory's name, we could
295  // potentially infer that it's the same and return "." for this.
296  EXPECT_EQ("../bar",
297            RebaseSourceAbsolutePath("//foo/bar", SourceDir("//foo/bar/")));
298}
299
300TEST(FilesystemUtils, DirectoryWithNoLastSlash) {
301  EXPECT_EQ("", DirectoryWithNoLastSlash(SourceDir()));
302  EXPECT_EQ("/.", DirectoryWithNoLastSlash(SourceDir("/")));
303  EXPECT_EQ("//.", DirectoryWithNoLastSlash(SourceDir("//")));
304  EXPECT_EQ("//foo", DirectoryWithNoLastSlash(SourceDir("//foo/")));
305  EXPECT_EQ("/bar", DirectoryWithNoLastSlash(SourceDir("/bar/")));
306}
307
308TEST(FilesystemUtils, SourceDirForPath) {
309#if defined(OS_WIN)
310  base::FilePath root(L"C:\\source\\foo\\");
311  EXPECT_EQ("/C:/foo/bar/", SourceDirForPath(root,
312            base::FilePath(L"C:\\foo\\bar")).value());
313  EXPECT_EQ("/", SourceDirForPath(root,
314            base::FilePath(L"/")).value());
315  EXPECT_EQ("//", SourceDirForPath(root,
316            base::FilePath(L"C:\\source\\foo")).value());
317  EXPECT_EQ("//bar/", SourceDirForPath(root,
318            base::FilePath(L"C:\\source\\foo\\bar\\")). value());
319  EXPECT_EQ("//bar/baz/", SourceDirForPath(root,
320            base::FilePath(L"C:\\source\\foo\\bar\\baz")).value());
321
322  // Should be case-and-slash-insensitive.
323  EXPECT_EQ("//baR/", SourceDirForPath(root,
324            base::FilePath(L"c:/SOURCE\\Foo/baR/")).value());
325
326  // Some "weird" Windows paths.
327  EXPECT_EQ("/foo/bar/", SourceDirForPath(root,
328            base::FilePath(L"/foo/bar/")).value());
329  EXPECT_EQ("/C:/foo/bar/", SourceDirForPath(root,
330            base::FilePath(L"C:foo/bar/")).value());
331
332  // Also allow absolute GN-style Windows paths.
333  EXPECT_EQ("/C:/foo/bar/", SourceDirForPath(root,
334            base::FilePath(L"/C:/foo/bar")).value());
335  EXPECT_EQ("//bar/", SourceDirForPath(root,
336            base::FilePath(L"/C:/source/foo/bar")).value());
337
338#else
339  base::FilePath root("/source/foo/");
340  EXPECT_EQ("/foo/bar/", SourceDirForPath(root,
341            base::FilePath("/foo/bar/")).value());
342  EXPECT_EQ("/", SourceDirForPath(root,
343            base::FilePath("/")).value());
344  EXPECT_EQ("//", SourceDirForPath(root,
345            base::FilePath("/source/foo")).value());
346  EXPECT_EQ("//bar/", SourceDirForPath(root,
347            base::FilePath("/source/foo/bar/")).value());
348  EXPECT_EQ("//bar/baz/", SourceDirForPath(root,
349            base::FilePath("/source/foo/bar/baz/")).value());
350
351  // Should be case-sensitive.
352  EXPECT_EQ("/SOURCE/foo/bar/", SourceDirForPath(root,
353            base::FilePath("/SOURCE/foo/bar/")).value());
354#endif
355}
356
357TEST(FilesystemUtils, GetToolchainDirs) {
358  BuildSettings build_settings;
359  build_settings.SetBuildDir(SourceDir("//out/Debug/"));
360
361  // The default toolchain.
362  Settings default_settings(&build_settings, "");
363  Label default_toolchain_label(SourceDir("//toolchain/"), "default");
364  default_settings.set_toolchain_label(default_toolchain_label);
365  default_settings.set_default_toolchain_label(default_toolchain_label);
366
367  // Default toolchain out dir.
368  EXPECT_EQ("//out/Debug/",
369            GetToolchainOutputDir(&default_settings).value());
370  EXPECT_EQ("//out/Debug/",
371            GetToolchainOutputDir(&build_settings, default_toolchain_label,
372                                  true).value());
373
374  // Default toolchain gen dir.
375  EXPECT_EQ("//out/Debug/gen/",
376            GetToolchainGenDir(&default_settings).value());
377  EXPECT_EQ("gen/",
378            GetToolchainGenDirAsOutputFile(&default_settings).value());
379  EXPECT_EQ("//out/Debug/gen/",
380            GetToolchainGenDir(&build_settings, default_toolchain_label,
381                               true).value());
382
383  // Check a secondary toolchain.
384  Settings other_settings(&build_settings, "two/");
385  Label other_toolchain_label(SourceDir("//toolchain/"), "two");
386  default_settings.set_toolchain_label(other_toolchain_label);
387  default_settings.set_default_toolchain_label(default_toolchain_label);
388
389  // Secondary toolchain out dir.
390  EXPECT_EQ("//out/Debug/two/",
391            GetToolchainOutputDir(&other_settings).value());
392  EXPECT_EQ("//out/Debug/two/",
393            GetToolchainOutputDir(&build_settings, other_toolchain_label,
394                                  false).value());
395
396  // Secondary toolchain gen dir.
397  EXPECT_EQ("//out/Debug/two/gen/",
398            GetToolchainGenDir(&other_settings).value());
399  EXPECT_EQ("two/gen/",
400            GetToolchainGenDirAsOutputFile(&other_settings).value());
401  EXPECT_EQ("//out/Debug/two/gen/",
402            GetToolchainGenDir(&build_settings, other_toolchain_label,
403                               false).value());
404}
405
406TEST(FilesystemUtils, GetOutDirForSourceDir) {
407  BuildSettings build_settings;
408  build_settings.SetBuildDir(SourceDir("//out/Debug/"));
409
410  // Test the default toolchain.
411  Settings default_settings(&build_settings, "");
412  EXPECT_EQ("//out/Debug/obj/",
413            GetOutputDirForSourceDir(
414                &default_settings, SourceDir("//")).value());
415  EXPECT_EQ("obj/",
416            GetOutputDirForSourceDirAsOutputFile(
417                &default_settings, SourceDir("//")).value());
418
419  EXPECT_EQ("//out/Debug/obj/foo/bar/",
420            GetOutputDirForSourceDir(
421                &default_settings, SourceDir("//foo/bar/")).value());
422  EXPECT_EQ("obj/foo/bar/",
423            GetOutputDirForSourceDirAsOutputFile(
424                &default_settings, SourceDir("//foo/bar/")).value());
425
426  // Secondary toolchain.
427  Settings other_settings(&build_settings, "two/");
428  EXPECT_EQ("//out/Debug/two/obj/",
429            GetOutputDirForSourceDir(
430                &other_settings, SourceDir("//")).value());
431  EXPECT_EQ("two/obj/",
432            GetOutputDirForSourceDirAsOutputFile(
433                &other_settings, SourceDir("//")).value());
434
435  EXPECT_EQ("//out/Debug/two/obj/foo/bar/",
436            GetOutputDirForSourceDir(&other_settings,
437                                     SourceDir("//foo/bar/")).value());
438  EXPECT_EQ("two/obj/foo/bar/",
439            GetOutputDirForSourceDirAsOutputFile(
440                &other_settings, SourceDir("//foo/bar/")).value());
441}
442
443TEST(FilesystemUtils, GetGenDirForSourceDir) {
444  BuildSettings build_settings;
445  build_settings.SetBuildDir(SourceDir("//out/Debug/"));
446
447  // Test the default toolchain.
448  Settings default_settings(&build_settings, "");
449  EXPECT_EQ("//out/Debug/gen/",
450            GetGenDirForSourceDir(
451                &default_settings, SourceDir("//")).value());
452  EXPECT_EQ("gen/",
453            GetGenDirForSourceDirAsOutputFile(
454                &default_settings, SourceDir("//")).value());
455
456  EXPECT_EQ("//out/Debug/gen/foo/bar/",
457            GetGenDirForSourceDir(
458                &default_settings, SourceDir("//foo/bar/")).value());
459  EXPECT_EQ("gen/foo/bar/",
460            GetGenDirForSourceDirAsOutputFile(
461                &default_settings, SourceDir("//foo/bar/")).value());
462
463  // Secondary toolchain.
464  Settings other_settings(&build_settings, "two/");
465  EXPECT_EQ("//out/Debug/two/gen/",
466            GetGenDirForSourceDir(
467                &other_settings, SourceDir("//")).value());
468  EXPECT_EQ("two/gen/",
469            GetGenDirForSourceDirAsOutputFile(
470                &other_settings, SourceDir("//")).value());
471
472  EXPECT_EQ("//out/Debug/two/gen/foo/bar/",
473            GetGenDirForSourceDir(
474                &other_settings, SourceDir("//foo/bar/")).value());
475  EXPECT_EQ("two/gen/foo/bar/",
476            GetGenDirForSourceDirAsOutputFile(
477                &other_settings, SourceDir("//foo/bar/")).value());
478}
479
480TEST(FilesystemUtils, GetTargetDirs) {
481  BuildSettings build_settings;
482  build_settings.SetBuildDir(SourceDir("//out/Debug/"));
483  Settings settings(&build_settings, "");
484
485  Target a(&settings, Label(SourceDir("//foo/bar/"), "baz"));
486  EXPECT_EQ("//out/Debug/obj/foo/bar/", GetTargetOutputDir(&a).value());
487  EXPECT_EQ("obj/foo/bar/", GetTargetOutputDirAsOutputFile(&a).value());
488  EXPECT_EQ("//out/Debug/gen/foo/bar/", GetTargetGenDir(&a).value());
489  EXPECT_EQ("gen/foo/bar/", GetTargetGenDirAsOutputFile(&a).value());
490}
491
492// Tests handling of output dirs when build dir is the same as the root.
493TEST(FilesystemUtils, GetDirForEmptyBuildDir) {
494  BuildSettings build_settings;
495  build_settings.SetBuildDir(SourceDir("//"));
496  Settings settings(&build_settings, "");
497
498  EXPECT_EQ("//", GetToolchainOutputDir(&settings).value());
499  EXPECT_EQ("//gen/", GetToolchainGenDir(&settings).value());
500  EXPECT_EQ("gen/", GetToolchainGenDirAsOutputFile(&settings).value());
501  EXPECT_EQ("//obj/",
502            GetOutputDirForSourceDir(&settings, SourceDir("//")).value());
503  EXPECT_EQ("obj/",
504            GetOutputDirForSourceDirAsOutputFile(
505                &settings, SourceDir("//")).value());
506  EXPECT_EQ("gen/",
507            GetGenDirForSourceDirAsOutputFile(
508                &settings, SourceDir("//")).value());
509}
510