1 // Copyright (c) 2012 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 <stddef.h>
6 
7 #include <sstream>
8 
9 #include "base/files/file_path.h"
10 #include "base/stl_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/platform_test.h"
15 
16 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
17 #include "base/test/scoped_locale.h"
18 #endif
19 
20 // This macro helps avoid wrapped lines in the test structs.
21 #define FPL(x) FILE_PATH_LITERAL(x)
22 
23 // This macro constructs strings which can contain NULs.
24 #define FPS(x) FilePath::StringType(FPL(x), base::size(FPL(x)) - 1)
25 
26 namespace base {
27 
28 struct UnaryTestData {
29   FilePath::StringPieceType input;
30   FilePath::StringPieceType expected;
31 };
32 
33 struct UnaryBooleanTestData {
34   FilePath::StringPieceType input;
35   bool expected;
36 };
37 
38 struct BinaryTestData {
39   FilePath::StringPieceType inputs[2];
40   FilePath::StringPieceType expected;
41 };
42 
43 struct BinaryBooleanTestData {
44   FilePath::StringPieceType inputs[2];
45   bool expected;
46 };
47 
48 struct BinaryIntTestData {
49   FilePath::StringPieceType inputs[2];
50   int expected;
51 };
52 
53 struct UTF8TestData {
54   FilePath::StringPieceType native;
55   StringPiece utf8;
56 };
57 
58 // file_util winds up using autoreleased objects on the Mac, so this needs
59 // to be a PlatformTest
60 typedef PlatformTest FilePathTest;
61 
TEST_F(FilePathTest,DirName)62 TEST_F(FilePathTest, DirName) {
63   const struct UnaryTestData cases[] = {
64     { FPL(""),              FPL(".") },
65     { FPL("aa"),            FPL(".") },
66     { FPL("/aa/bb"),        FPL("/aa") },
67     { FPL("/aa/bb/"),       FPL("/aa") },
68     { FPL("/aa/bb//"),      FPL("/aa") },
69     { FPL("/aa/bb/ccc"),    FPL("/aa/bb") },
70     { FPL("/aa"),           FPL("/") },
71     { FPL("/aa/"),          FPL("/") },
72     { FPL("/"),             FPL("/") },
73     { FPL("//"),            FPL("//") },
74     { FPL("///"),           FPL("/") },
75     { FPL("aa/"),           FPL(".") },
76     { FPL("aa/bb"),         FPL("aa") },
77     { FPL("aa/bb/"),        FPL("aa") },
78     { FPL("aa/bb//"),       FPL("aa") },
79     { FPL("aa//bb//"),      FPL("aa") },
80     { FPL("aa//bb/"),       FPL("aa") },
81     { FPL("aa//bb"),        FPL("aa") },
82     { FPL("//aa/bb"),       FPL("//aa") },
83     { FPL("//aa/"),         FPL("//") },
84     { FPL("//aa"),          FPL("//") },
85     { FPL("0:"),            FPL(".") },
86     { FPL("@:"),            FPL(".") },
87     { FPL("[:"),            FPL(".") },
88     { FPL("`:"),            FPL(".") },
89     { FPL("{:"),            FPL(".") },
90     { FPL("\xB3:"),         FPL(".") },
91     { FPL("\xC5:"),         FPL(".") },
92     { FPL("/aa/../bb/cc"),  FPL("/aa/../bb")},
93 #if defined(OS_WIN)
94     { FPL("\x0143:"),       FPL(".") },
95 #endif  // OS_WIN
96 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
97     { FPL("c:"),            FPL("c:") },
98     { FPL("C:"),            FPL("C:") },
99     { FPL("A:"),            FPL("A:") },
100     { FPL("Z:"),            FPL("Z:") },
101     { FPL("a:"),            FPL("a:") },
102     { FPL("z:"),            FPL("z:") },
103     { FPL("c:aa"),          FPL("c:") },
104     { FPL("c:/"),           FPL("c:/") },
105     { FPL("c://"),          FPL("c://") },
106     { FPL("c:///"),         FPL("c:/") },
107     { FPL("c:/aa"),         FPL("c:/") },
108     { FPL("c:/aa/"),        FPL("c:/") },
109     { FPL("c:/aa/bb"),      FPL("c:/aa") },
110     { FPL("c:aa/bb"),       FPL("c:aa") },
111 #endif  // FILE_PATH_USES_DRIVE_LETTERS
112 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
113     { FPL("\\aa\\bb"),      FPL("\\aa") },
114     { FPL("\\aa\\bb\\"),    FPL("\\aa") },
115     { FPL("\\aa\\bb\\\\"),  FPL("\\aa") },
116     { FPL("\\aa\\bb\\ccc"), FPL("\\aa\\bb") },
117     { FPL("\\aa"),          FPL("\\") },
118     { FPL("\\aa\\"),        FPL("\\") },
119     { FPL("\\"),            FPL("\\") },
120     { FPL("\\\\"),          FPL("\\\\") },
121     { FPL("\\\\\\"),        FPL("\\") },
122     { FPL("aa\\"),          FPL(".") },
123     { FPL("aa\\bb"),        FPL("aa") },
124     { FPL("aa\\bb\\"),      FPL("aa") },
125     { FPL("aa\\bb\\\\"),    FPL("aa") },
126     { FPL("aa\\\\bb\\\\"),  FPL("aa") },
127     { FPL("aa\\\\bb\\"),    FPL("aa") },
128     { FPL("aa\\\\bb"),      FPL("aa") },
129     { FPL("\\\\aa\\bb"),    FPL("\\\\aa") },
130     { FPL("\\\\aa\\"),      FPL("\\\\") },
131     { FPL("\\\\aa"),        FPL("\\\\") },
132     { FPL("aa\\..\\bb\\c"), FPL("aa\\..\\bb")},
133 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
134     { FPL("c:\\"),          FPL("c:\\") },
135     { FPL("c:\\\\"),        FPL("c:\\\\") },
136     { FPL("c:\\\\\\"),      FPL("c:\\") },
137     { FPL("c:\\aa"),        FPL("c:\\") },
138     { FPL("c:\\aa\\"),      FPL("c:\\") },
139     { FPL("c:\\aa\\bb"),    FPL("c:\\aa") },
140     { FPL("c:aa\\bb"),      FPL("c:aa") },
141 #endif  // FILE_PATH_USES_DRIVE_LETTERS
142 #endif  // FILE_PATH_USES_WIN_SEPARATORS
143   };
144 
145   for (size_t i = 0; i < base::size(cases); ++i) {
146     FilePath input(cases[i].input);
147     FilePath observed = input.DirName();
148     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
149               "i: " << i << ", input: " << input.value();
150   }
151 }
152 
TEST_F(FilePathTest,BaseName)153 TEST_F(FilePathTest, BaseName) {
154   const struct UnaryTestData cases[] = {
155     { FPL(""),              FPL("") },
156     { FPL("aa"),            FPL("aa") },
157     { FPL("/aa/bb"),        FPL("bb") },
158     { FPL("/aa/bb/"),       FPL("bb") },
159     { FPL("/aa/bb//"),      FPL("bb") },
160     { FPL("/aa/bb/ccc"),    FPL("ccc") },
161     { FPL("/aa"),           FPL("aa") },
162     { FPL("/"),             FPL("/") },
163     { FPL("//"),            FPL("//") },
164     { FPL("///"),           FPL("/") },
165     { FPL("aa/"),           FPL("aa") },
166     { FPL("aa/bb"),         FPL("bb") },
167     { FPL("aa/bb/"),        FPL("bb") },
168     { FPL("aa/bb//"),       FPL("bb") },
169     { FPL("aa//bb//"),      FPL("bb") },
170     { FPL("aa//bb/"),       FPL("bb") },
171     { FPL("aa//bb"),        FPL("bb") },
172     { FPL("//aa/bb"),       FPL("bb") },
173     { FPL("//aa/"),         FPL("aa") },
174     { FPL("//aa"),          FPL("aa") },
175     { FPL("0:"),            FPL("0:") },
176     { FPL("@:"),            FPL("@:") },
177     { FPL("[:"),            FPL("[:") },
178     { FPL("`:"),            FPL("`:") },
179     { FPL("{:"),            FPL("{:") },
180     { FPL("\xB3:"),         FPL("\xB3:") },
181     { FPL("\xC5:"),         FPL("\xC5:") },
182 #if defined(OS_WIN)
183     { FPL("\x0143:"),       FPL("\x0143:") },
184 #endif  // OS_WIN
185 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
186     { FPL("c:"),            FPL("") },
187     { FPL("C:"),            FPL("") },
188     { FPL("A:"),            FPL("") },
189     { FPL("Z:"),            FPL("") },
190     { FPL("a:"),            FPL("") },
191     { FPL("z:"),            FPL("") },
192     { FPL("c:aa"),          FPL("aa") },
193     { FPL("c:/"),           FPL("/") },
194     { FPL("c://"),          FPL("//") },
195     { FPL("c:///"),         FPL("/") },
196     { FPL("c:/aa"),         FPL("aa") },
197     { FPL("c:/aa/"),        FPL("aa") },
198     { FPL("c:/aa/bb"),      FPL("bb") },
199     { FPL("c:aa/bb"),       FPL("bb") },
200 #endif  // FILE_PATH_USES_DRIVE_LETTERS
201 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
202     { FPL("\\aa\\bb"),      FPL("bb") },
203     { FPL("\\aa\\bb\\"),    FPL("bb") },
204     { FPL("\\aa\\bb\\\\"),  FPL("bb") },
205     { FPL("\\aa\\bb\\ccc"), FPL("ccc") },
206     { FPL("\\aa"),          FPL("aa") },
207     { FPL("\\"),            FPL("\\") },
208     { FPL("\\\\"),          FPL("\\\\") },
209     { FPL("\\\\\\"),        FPL("\\") },
210     { FPL("aa\\"),          FPL("aa") },
211     { FPL("aa\\bb"),        FPL("bb") },
212     { FPL("aa\\bb\\"),      FPL("bb") },
213     { FPL("aa\\bb\\\\"),    FPL("bb") },
214     { FPL("aa\\\\bb\\\\"),  FPL("bb") },
215     { FPL("aa\\\\bb\\"),    FPL("bb") },
216     { FPL("aa\\\\bb"),      FPL("bb") },
217     { FPL("\\\\aa\\bb"),    FPL("bb") },
218     { FPL("\\\\aa\\"),      FPL("aa") },
219     { FPL("\\\\aa"),        FPL("aa") },
220 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
221     { FPL("c:\\"),          FPL("\\") },
222     { FPL("c:\\\\"),        FPL("\\\\") },
223     { FPL("c:\\\\\\"),      FPL("\\") },
224     { FPL("c:\\aa"),        FPL("aa") },
225     { FPL("c:\\aa\\"),      FPL("aa") },
226     { FPL("c:\\aa\\bb"),    FPL("bb") },
227     { FPL("c:aa\\bb"),      FPL("bb") },
228 #endif  // FILE_PATH_USES_DRIVE_LETTERS
229 #endif  // FILE_PATH_USES_WIN_SEPARATORS
230   };
231 
232   for (size_t i = 0; i < base::size(cases); ++i) {
233     FilePath input(cases[i].input);
234     FilePath observed = input.BaseName();
235     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
236               "i: " << i << ", input: " << input.value();
237   }
238 }
239 
TEST_F(FilePathTest,Append)240 TEST_F(FilePathTest, Append) {
241   const struct BinaryTestData cases[] = {
242     { { FPL(""),           FPL("cc") }, FPL("cc") },
243     { { FPL("."),          FPL("ff") }, FPL("ff") },
244     { { FPL("."),          FPL("") },   FPL(".") },
245     { { FPL("/"),          FPL("cc") }, FPL("/cc") },
246     { { FPL("/aa"),        FPL("") },   FPL("/aa") },
247     { { FPL("/aa/"),       FPL("") },   FPL("/aa") },
248     { { FPL("//aa"),       FPL("") },   FPL("//aa") },
249     { { FPL("//aa/"),      FPL("") },   FPL("//aa") },
250     { { FPL("//"),         FPL("aa") }, FPL("//aa") },
251 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
252     { { FPL("c:"),         FPL("a") },  FPL("c:a") },
253     { { FPL("c:"),         FPL("") },   FPL("c:") },
254     { { FPL("c:/"),        FPL("a") },  FPL("c:/a") },
255     { { FPL("c://"),       FPL("a") },  FPL("c://a") },
256     { { FPL("c:///"),      FPL("a") },  FPL("c:/a") },
257 #endif  // FILE_PATH_USES_DRIVE_LETTERS
258 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
259     // Append introduces the default separator character, so these test cases
260     // need to be defined with different expected results on platforms that use
261     // different default separator characters.
262     { { FPL("\\"),         FPL("cc") }, FPL("\\cc") },
263     { { FPL("\\aa"),       FPL("") },   FPL("\\aa") },
264     { { FPL("\\aa\\"),     FPL("") },   FPL("\\aa") },
265     { { FPL("\\\\aa"),     FPL("") },   FPL("\\\\aa") },
266     { { FPL("\\\\aa\\"),   FPL("") },   FPL("\\\\aa") },
267     { { FPL("\\\\"),       FPL("aa") }, FPL("\\\\aa") },
268     { { FPL("/aa/bb"),     FPL("cc") }, FPL("/aa/bb\\cc") },
269     { { FPL("/aa/bb/"),    FPL("cc") }, FPL("/aa/bb\\cc") },
270     { { FPL("aa/bb/"),     FPL("cc") }, FPL("aa/bb\\cc") },
271     { { FPL("aa/bb"),      FPL("cc") }, FPL("aa/bb\\cc") },
272     { { FPL("a/b"),        FPL("c") },  FPL("a/b\\c") },
273     { { FPL("a/b/"),       FPL("c") },  FPL("a/b\\c") },
274     { { FPL("//aa"),       FPL("bb") }, FPL("//aa\\bb") },
275     { { FPL("//aa/"),      FPL("bb") }, FPL("//aa\\bb") },
276     { { FPL("\\aa\\bb"),   FPL("cc") }, FPL("\\aa\\bb\\cc") },
277     { { FPL("\\aa\\bb\\"), FPL("cc") }, FPL("\\aa\\bb\\cc") },
278     { { FPL("aa\\bb\\"),   FPL("cc") }, FPL("aa\\bb\\cc") },
279     { { FPL("aa\\bb"),     FPL("cc") }, FPL("aa\\bb\\cc") },
280     { { FPL("a\\b"),       FPL("c") },  FPL("a\\b\\c") },
281     { { FPL("a\\b\\"),     FPL("c") },  FPL("a\\b\\c") },
282     { { FPL("\\\\aa"),     FPL("bb") }, FPL("\\\\aa\\bb") },
283     { { FPL("\\\\aa\\"),   FPL("bb") }, FPL("\\\\aa\\bb") },
284 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
285     { { FPL("c:\\"),       FPL("a") },  FPL("c:\\a") },
286     { { FPL("c:\\\\"),     FPL("a") },  FPL("c:\\\\a") },
287     { { FPL("c:\\\\\\"),   FPL("a") },  FPL("c:\\a") },
288     { { FPL("c:\\"),       FPL("") },   FPL("c:\\") },
289     { { FPL("c:\\a"),      FPL("b") },  FPL("c:\\a\\b") },
290     { { FPL("c:\\a\\"),    FPL("b") },  FPL("c:\\a\\b") },
291 #endif  // FILE_PATH_USES_DRIVE_LETTERS
292 #else  // FILE_PATH_USES_WIN_SEPARATORS
293     { { FPL("/aa/bb"),     FPL("cc") }, FPL("/aa/bb/cc") },
294     { { FPL("/aa/bb/"),    FPL("cc") }, FPL("/aa/bb/cc") },
295     { { FPL("aa/bb/"),     FPL("cc") }, FPL("aa/bb/cc") },
296     { { FPL("aa/bb"),      FPL("cc") }, FPL("aa/bb/cc") },
297     { { FPL("a/b"),        FPL("c") },  FPL("a/b/c") },
298     { { FPL("a/b/"),       FPL("c") },  FPL("a/b/c") },
299     { { FPL("//aa"),       FPL("bb") }, FPL("//aa/bb") },
300     { { FPL("//aa/"),      FPL("bb") }, FPL("//aa/bb") },
301 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
302     { { FPL("c:/"),        FPL("a") },  FPL("c:/a") },
303     { { FPL("c:/"),        FPL("") },   FPL("c:/") },
304     { { FPL("c:/a"),       FPL("b") },  FPL("c:/a/b") },
305     { { FPL("c:/a/"),      FPL("b") },  FPL("c:/a/b") },
306 #endif  // FILE_PATH_USES_DRIVE_LETTERS
307 #endif  // FILE_PATH_USES_WIN_SEPARATORS
308   };
309 
310   for (size_t i = 0; i < base::size(cases); ++i) {
311     FilePath root(cases[i].inputs[0]);
312     FilePath::StringType leaf(cases[i].inputs[1]);
313     FilePath observed_str = root.Append(leaf);
314     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) <<
315               "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
316     FilePath observed_path = root.Append(FilePath(leaf));
317     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_path.value()) <<
318               "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
319 
320     // TODO(erikkay): It would be nice to have a unicode test append value to
321     // handle the case when AppendASCII is passed UTF8
322 #if defined(OS_WIN)
323     std::string ascii = WideToUTF8(leaf);
324 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
325     std::string ascii = leaf;
326 #endif
327     observed_str = root.AppendASCII(ascii);
328     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) <<
329               "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
330   }
331 }
332 
TEST_F(FilePathTest,StripTrailingSeparators)333 TEST_F(FilePathTest, StripTrailingSeparators) {
334   const struct UnaryTestData cases[] = {
335     { FPL(""),              FPL("") },
336     { FPL("/"),             FPL("/") },
337     { FPL("//"),            FPL("//") },
338     { FPL("///"),           FPL("/") },
339     { FPL("////"),          FPL("/") },
340     { FPL("a/"),            FPL("a") },
341     { FPL("a//"),           FPL("a") },
342     { FPL("a///"),          FPL("a") },
343     { FPL("a////"),         FPL("a") },
344     { FPL("/a"),            FPL("/a") },
345     { FPL("/a/"),           FPL("/a") },
346     { FPL("/a//"),          FPL("/a") },
347     { FPL("/a///"),         FPL("/a") },
348     { FPL("/a////"),        FPL("/a") },
349 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
350     { FPL("c:"),            FPL("c:") },
351     { FPL("c:/"),           FPL("c:/") },
352     { FPL("c://"),          FPL("c://") },
353     { FPL("c:///"),         FPL("c:/") },
354     { FPL("c:////"),        FPL("c:/") },
355     { FPL("c:/a"),          FPL("c:/a") },
356     { FPL("c:/a/"),         FPL("c:/a") },
357     { FPL("c:/a//"),        FPL("c:/a") },
358     { FPL("c:/a///"),       FPL("c:/a") },
359     { FPL("c:/a////"),      FPL("c:/a") },
360 #endif  // FILE_PATH_USES_DRIVE_LETTERS
361 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
362     { FPL("\\"),            FPL("\\") },
363     { FPL("\\\\"),          FPL("\\\\") },
364     { FPL("\\\\\\"),        FPL("\\") },
365     { FPL("\\\\\\\\"),      FPL("\\") },
366     { FPL("a\\"),           FPL("a") },
367     { FPL("a\\\\"),         FPL("a") },
368     { FPL("a\\\\\\"),       FPL("a") },
369     { FPL("a\\\\\\\\"),     FPL("a") },
370     { FPL("\\a"),           FPL("\\a") },
371     { FPL("\\a\\"),         FPL("\\a") },
372     { FPL("\\a\\\\"),       FPL("\\a") },
373     { FPL("\\a\\\\\\"),     FPL("\\a") },
374     { FPL("\\a\\\\\\\\"),   FPL("\\a") },
375 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
376     { FPL("c:\\"),          FPL("c:\\") },
377     { FPL("c:\\\\"),        FPL("c:\\\\") },
378     { FPL("c:\\\\\\"),      FPL("c:\\") },
379     { FPL("c:\\\\\\\\"),    FPL("c:\\") },
380     { FPL("c:\\a"),         FPL("c:\\a") },
381     { FPL("c:\\a\\"),       FPL("c:\\a") },
382     { FPL("c:\\a\\\\"),     FPL("c:\\a") },
383     { FPL("c:\\a\\\\\\"),   FPL("c:\\a") },
384     { FPL("c:\\a\\\\\\\\"), FPL("c:\\a") },
385 #endif  // FILE_PATH_USES_DRIVE_LETTERS
386 #endif  // FILE_PATH_USES_WIN_SEPARATORS
387   };
388 
389   for (size_t i = 0; i < base::size(cases); ++i) {
390     FilePath input(cases[i].input);
391     FilePath observed = input.StripTrailingSeparators();
392     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
393               "i: " << i << ", input: " << input.value();
394   }
395 }
396 
TEST_F(FilePathTest,IsAbsolute)397 TEST_F(FilePathTest, IsAbsolute) {
398   const struct UnaryBooleanTestData cases[] = {
399     { FPL(""),       false },
400     { FPL("a"),      false },
401     { FPL("c:"),     false },
402     { FPL("c:a"),    false },
403     { FPL("a/b"),    false },
404     { FPL("//"),     true },
405     { FPL("//a"),    true },
406     { FPL("c:a/b"),  false },
407     { FPL("?:/a"),   false },
408 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
409     { FPL("/"),      false },
410     { FPL("/a"),     false },
411     { FPL("/."),     false },
412     { FPL("/.."),    false },
413     { FPL("c:/"),    true },
414     { FPL("c:/a"),   true },
415     { FPL("c:/."),   true },
416     { FPL("c:/.."),  true },
417     { FPL("C:/a"),   true },
418     { FPL("d:/a"),   true },
419 #else  // FILE_PATH_USES_DRIVE_LETTERS
420     { FPL("/"),      true },
421     { FPL("/a"),     true },
422     { FPL("/."),     true },
423     { FPL("/.."),    true },
424     { FPL("c:/"),    false },
425 #endif  // FILE_PATH_USES_DRIVE_LETTERS
426 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
427     { FPL("a\\b"),   false },
428     { FPL("\\\\"),   true },
429     { FPL("\\\\a"),  true },
430     { FPL("a\\b"),   false },
431     { FPL("\\\\"),   true },
432     { FPL("//a"),    true },
433     { FPL("c:a\\b"), false },
434     { FPL("?:\\a"),  false },
435 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
436     { FPL("\\"),     false },
437     { FPL("\\a"),    false },
438     { FPL("\\."),    false },
439     { FPL("\\.."),   false },
440     { FPL("c:\\"),   true },
441     { FPL("c:\\"),   true },
442     { FPL("c:\\a"),  true },
443     { FPL("c:\\."),  true },
444     { FPL("c:\\.."), true },
445     { FPL("C:\\a"),  true },
446     { FPL("d:\\a"),  true },
447 #else  // FILE_PATH_USES_DRIVE_LETTERS
448     { FPL("\\"),     true },
449     { FPL("\\a"),    true },
450     { FPL("\\."),    true },
451     { FPL("\\.."),   true },
452     { FPL("c:\\"),   false },
453 #endif  // FILE_PATH_USES_DRIVE_LETTERS
454 #endif  // FILE_PATH_USES_WIN_SEPARATORS
455   };
456 
457   for (size_t i = 0; i < base::size(cases); ++i) {
458     FilePath input(cases[i].input);
459     bool observed = input.IsAbsolute();
460     EXPECT_EQ(cases[i].expected, observed) <<
461               "i: " << i << ", input: " << input.value();
462   }
463 }
464 
TEST_F(FilePathTest,PathComponentsTest)465 TEST_F(FilePathTest, PathComponentsTest) {
466   const struct UnaryTestData cases[] = {
467     { FPL("//foo/bar/baz/"),          FPL("|//|foo|bar|baz")},
468     { FPL("///"),                     FPL("|/")},
469     { FPL("/foo//bar//baz/"),         FPL("|/|foo|bar|baz")},
470     { FPL("/foo/bar/baz/"),           FPL("|/|foo|bar|baz")},
471     { FPL("/foo/bar/baz//"),          FPL("|/|foo|bar|baz")},
472     { FPL("/foo/bar/baz///"),         FPL("|/|foo|bar|baz")},
473     { FPL("/foo/bar/baz"),            FPL("|/|foo|bar|baz")},
474     { FPL("/foo/bar.bot/baz.txt"),    FPL("|/|foo|bar.bot|baz.txt")},
475     { FPL("//foo//bar/baz"),          FPL("|//|foo|bar|baz")},
476     { FPL("/"),                       FPL("|/")},
477     { FPL("foo"),                     FPL("|foo")},
478     { FPL(""),                        FPL("")},
479 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
480     { FPL("e:/foo"),                  FPL("|e:|/|foo")},
481     { FPL("e:/"),                     FPL("|e:|/")},
482     { FPL("e:"),                      FPL("|e:")},
483 #endif  // FILE_PATH_USES_DRIVE_LETTERS
484 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
485     { FPL("../foo"),                  FPL("|..|foo")},
486     { FPL("./foo"),                   FPL("|foo")},
487     { FPL("../foo/bar/"),             FPL("|..|foo|bar") },
488     { FPL("\\\\foo\\bar\\baz\\"),     FPL("|\\\\|foo|bar|baz")},
489     { FPL("\\\\\\"),                  FPL("|\\")},
490     { FPL("\\foo\\\\bar\\\\baz\\"),   FPL("|\\|foo|bar|baz")},
491     { FPL("\\foo\\bar\\baz\\"),       FPL("|\\|foo|bar|baz")},
492     { FPL("\\foo\\bar\\baz\\\\"),     FPL("|\\|foo|bar|baz")},
493     { FPL("\\foo\\bar\\baz\\\\\\"),   FPL("|\\|foo|bar|baz")},
494     { FPL("\\foo\\bar\\baz"),         FPL("|\\|foo|bar|baz")},
495     { FPL("\\foo\\bar/baz\\\\\\"),    FPL("|\\|foo|bar|baz")},
496     { FPL("/foo\\bar\\baz"),          FPL("|/|foo|bar|baz")},
497     { FPL("\\foo\\bar.bot\\baz.txt"), FPL("|\\|foo|bar.bot|baz.txt")},
498     { FPL("\\\\foo\\\\bar\\baz"),     FPL("|\\\\|foo|bar|baz")},
499     { FPL("\\"),                      FPL("|\\")},
500 #endif  // FILE_PATH_USES_WIN_SEPARATORS
501   };
502 
503   for (size_t i = 0; i < base::size(cases); ++i) {
504     FilePath input(cases[i].input);
505     std::vector<FilePath::StringType> comps;
506     input.GetComponents(&comps);
507 
508     FilePath::StringType observed;
509     for (const auto& j : comps) {
510       observed.append(FILE_PATH_LITERAL("|"), 1);
511       observed.append(j);
512     }
513     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed) <<
514               "i: " << i << ", input: " << input.value();
515   }
516 }
517 
TEST_F(FilePathTest,IsParentTest)518 TEST_F(FilePathTest, IsParentTest) {
519   const struct BinaryBooleanTestData cases[] = {
520     { { FPL("/"),             FPL("/foo/bar/baz") },      true},
521     { { FPL("/foo"),          FPL("/foo/bar/baz") },      true},
522     { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      true},
523     { { FPL("/foo/bar/"),     FPL("/foo/bar/baz") },      true},
524     { { FPL("//foo/bar/"),    FPL("//foo/bar/baz") },     true},
525     { { FPL("/foo/bar"),      FPL("/foo2/bar/baz") },     false},
526     { { FPL("/foo/bar.txt"),  FPL("/foo/bar/baz") },      false},
527     { { FPL("/foo/bar"),      FPL("/foo/bar2/baz") },     false},
528     { { FPL("/foo/bar"),      FPL("/foo/bar") },          false},
529     { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          false},
530     { { FPL("foo"),           FPL("foo/bar/baz") },       true},
531     { { FPL("foo/bar"),       FPL("foo/bar/baz") },       true},
532     { { FPL("foo/bar"),       FPL("foo2/bar/baz") },      false},
533     { { FPL("foo/bar"),       FPL("foo/bar2/baz") },      false},
534     { { FPL(""),              FPL("foo") },               false},
535 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
536     { { FPL("c:/foo/bar"),    FPL("c:/foo/bar/baz") },    true},
537     { { FPL("E:/foo/bar"),    FPL("e:/foo/bar/baz") },    true},
538     { { FPL("f:/foo/bar"),    FPL("F:/foo/bar/baz") },    true},
539     { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar/baz") },    false},
540     { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar/baz") },    false},
541     { { FPL("c:/"),           FPL("c:/foo/bar/baz") },    true},
542     { { FPL("c:"),            FPL("c:/foo/bar/baz") },    true},
543     { { FPL("c:/foo/bar"),    FPL("d:/foo/bar/baz") },    false},
544     { { FPL("c:/foo/bar"),    FPL("D:/foo/bar/baz") },    false},
545     { { FPL("C:/foo/bar"),    FPL("d:/foo/bar/baz") },    false},
546     { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar/baz") },   false},
547     { { FPL("e:/foo/bar"),    FPL("E:/foo2/bar/baz") },   false},
548     { { FPL("F:/foo/bar"),    FPL("f:/foo2/bar/baz") },   false},
549     { { FPL("c:/foo/bar"),    FPL("c:/foo/bar2/baz") },   false},
550 #endif  // FILE_PATH_USES_DRIVE_LETTERS
551 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
552     { { FPL("\\foo\\bar"),    FPL("\\foo\\bar\\baz") },   true},
553     { { FPL("\\foo/bar"),     FPL("\\foo\\bar\\baz") },   true},
554     { { FPL("\\foo/bar"),     FPL("\\foo/bar/baz") },     true},
555     { { FPL("\\"),            FPL("\\foo\\bar\\baz") },   true},
556     { { FPL(""),              FPL("\\foo\\bar\\baz") },   false},
557     { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar\\baz") },  false},
558     { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2\\baz") },  false},
559 #endif  // FILE_PATH_USES_WIN_SEPARATORS
560   };
561 
562   for (size_t i = 0; i < base::size(cases); ++i) {
563     FilePath parent(cases[i].inputs[0]);
564     FilePath child(cases[i].inputs[1]);
565 
566     EXPECT_EQ(parent.IsParent(child), cases[i].expected) <<
567         "i: " << i << ", parent: " << parent.value() << ", child: " <<
568         child.value();
569   }
570 }
571 
TEST_F(FilePathTest,AppendRelativePathTest)572 TEST_F(FilePathTest, AppendRelativePathTest) {
573   const struct BinaryTestData cases[] = {
574 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
575     { { FPL("/"),             FPL("/foo/bar/baz") },      FPL("foo\\bar\\baz")},
576 #else  // FILE_PATH_USES_WIN_SEPARATORS
577     { { FPL("/"),             FPL("/foo/bar/baz") },      FPL("foo/bar/baz")},
578 #endif  // FILE_PATH_USES_WIN_SEPARATORS
579     { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      FPL("baz")},
580     { { FPL("/foo/bar/"),     FPL("/foo/bar/baz") },      FPL("baz")},
581     { { FPL("//foo/bar/"),    FPL("//foo/bar/baz") },     FPL("baz")},
582     { { FPL("/foo/bar"),      FPL("/foo2/bar/baz") },     FPL("")},
583     { { FPL("/foo/bar.txt"),  FPL("/foo/bar/baz") },      FPL("")},
584     { { FPL("/foo/bar"),      FPL("/foo/bar2/baz") },     FPL("")},
585     { { FPL("/foo/bar"),      FPL("/foo/bar") },          FPL("")},
586     { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          FPL("")},
587     { { FPL("foo/bar"),       FPL("foo/bar/baz") },       FPL("baz")},
588     { { FPL("foo/bar"),       FPL("foo2/bar/baz") },      FPL("")},
589     { { FPL("foo/bar"),       FPL("foo/bar2/baz") },      FPL("")},
590     { { FPL(""),              FPL("foo") },               FPL("")},
591 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
592     { { FPL("c:/foo/bar"),    FPL("c:/foo/bar/baz") },    FPL("baz")},
593     { { FPL("E:/foo/bar"),    FPL("e:/foo/bar/baz") },    FPL("baz")},
594     { { FPL("f:/foo/bar"),    FPL("F:/foo/bar/baz") },    FPL("baz")},
595     { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar/baz") },    FPL("")},
596     { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar/baz") },    FPL("")},
597 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
598     { { FPL("c:/"),           FPL("c:/foo/bar/baz") },    FPL("foo\\bar\\baz")},
599     // TODO(akalin): Figure out how to handle the corner case in the
600     // commented-out test case below.  Appending to an empty path gives
601     // /foo\bar\baz but appending to a nonempty path "blah" gives
602     // blah\foo\bar\baz.
603     // { { FPL("c:"),            FPL("c:/foo/bar/baz") }, FPL("foo\\bar\\baz")},
604 #endif  // FILE_PATH_USES_WIN_SEPARATORS
605     { { FPL("c:/foo/bar"),    FPL("d:/foo/bar/baz") },    FPL("")},
606     { { FPL("c:/foo/bar"),    FPL("D:/foo/bar/baz") },    FPL("")},
607     { { FPL("C:/foo/bar"),    FPL("d:/foo/bar/baz") },    FPL("")},
608     { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar/baz") },   FPL("")},
609     { { FPL("e:/foo/bar"),    FPL("E:/foo2/bar/baz") },   FPL("")},
610     { { FPL("F:/foo/bar"),    FPL("f:/foo2/bar/baz") },   FPL("")},
611     { { FPL("c:/foo/bar"),    FPL("c:/foo/bar2/baz") },   FPL("")},
612 #endif  // FILE_PATH_USES_DRIVE_LETTERS
613 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
614     { { FPL("\\foo\\bar"),    FPL("\\foo\\bar\\baz") },   FPL("baz")},
615     { { FPL("\\foo/bar"),     FPL("\\foo\\bar\\baz") },   FPL("baz")},
616     { { FPL("\\foo/bar"),     FPL("\\foo/bar/baz") },     FPL("baz")},
617     { { FPL("\\"),            FPL("\\foo\\bar\\baz") },   FPL("foo\\bar\\baz")},
618     { { FPL(""),              FPL("\\foo\\bar\\baz") },   FPL("")},
619     { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar\\baz") },  FPL("")},
620     { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2\\baz") },  FPL("")},
621 #endif  // FILE_PATH_USES_WIN_SEPARATORS
622   };
623 
624   const FilePath base(FPL("blah"));
625 
626   for (size_t i = 0; i < base::size(cases); ++i) {
627     FilePath parent(cases[i].inputs[0]);
628     FilePath child(cases[i].inputs[1]);
629     {
630       FilePath result;
631       bool success = parent.AppendRelativePath(child, &result);
632       EXPECT_EQ(!cases[i].expected.empty(), success)
633           << "i: " << i << ", parent: " << parent.value()
634           << ", child: " << child.value();
635       EXPECT_EQ(cases[i].expected, result.value())
636           << "i: " << i << ", parent: " << parent.value()
637           << ", child: " << child.value();
638     }
639     {
640       FilePath result(base);
641       bool success = parent.AppendRelativePath(child, &result);
642       EXPECT_EQ(!cases[i].expected.empty(), success)
643           << "i: " << i << ", parent: " << parent.value()
644           << ", child: " << child.value();
645       EXPECT_EQ(base.Append(cases[i].expected).value(), result.value()) <<
646         "i: " << i << ", parent: " << parent.value() << ", child: " <<
647         child.value();
648     }
649   }
650 }
651 
TEST_F(FilePathTest,EqualityTest)652 TEST_F(FilePathTest, EqualityTest) {
653   const struct BinaryBooleanTestData cases[] = {
654     { { FPL("/foo/bar/baz"),  FPL("/foo/bar/baz") },      true},
655     { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      false},
656     { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          false},
657     { { FPL("//foo/bar/"),    FPL("//foo/bar/") },        true},
658     { { FPL("/foo/bar"),      FPL("/foo2/bar") },         false},
659     { { FPL("/foo/bar.txt"),  FPL("/foo/bar") },          false},
660     { { FPL("foo/bar"),       FPL("foo/bar") },           true},
661     { { FPL("foo/bar"),       FPL("foo/bar/baz") },       false},
662     { { FPL(""),              FPL("foo") },               false},
663 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
664     { { FPL("c:/foo/bar"),    FPL("c:/foo/bar") },        true},
665     { { FPL("E:/foo/bar"),    FPL("e:/foo/bar") },        true},
666     { { FPL("f:/foo/bar"),    FPL("F:/foo/bar") },        true},
667     { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar") },        false},
668     { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar") },        false},
669     { { FPL("c:/"),           FPL("c:/") },               true},
670     { { FPL("c:"),            FPL("c:") },                true},
671     { { FPL("c:/foo/bar"),    FPL("d:/foo/bar") },        false},
672     { { FPL("c:/foo/bar"),    FPL("D:/foo/bar") },        false},
673     { { FPL("C:/foo/bar"),    FPL("d:/foo/bar") },        false},
674     { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar") },       false},
675 #endif  // FILE_PATH_USES_DRIVE_LETTERS
676 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
677     { { FPL("\\foo\\bar"),    FPL("\\foo\\bar") },        true},
678     { { FPL("\\foo/bar"),     FPL("\\foo/bar") },         true},
679     { { FPL("\\foo/bar"),     FPL("\\foo\\bar") },        false},
680     { { FPL("\\"),            FPL("\\") },                true},
681     { { FPL("\\"),            FPL("/") },                 false},
682     { { FPL(""),              FPL("\\") },                false},
683     { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar") },       false},
684     { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2") },       false},
685 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
686     { { FPL("c:\\foo\\bar"),    FPL("c:\\foo\\bar") },    true},
687     { { FPL("E:\\foo\\bar"),    FPL("e:\\foo\\bar") },    true},
688     { { FPL("f:\\foo\\bar"),    FPL("F:\\foo/bar") },     false},
689 #endif  // FILE_PATH_USES_DRIVE_LETTERS
690 #endif  // FILE_PATH_USES_WIN_SEPARATORS
691   };
692 
693   for (size_t i = 0; i < base::size(cases); ++i) {
694     FilePath a(cases[i].inputs[0]);
695     FilePath b(cases[i].inputs[1]);
696 
697     EXPECT_EQ(a == b, cases[i].expected) <<
698       "equality i: " << i << ", a: " << a.value() << ", b: " <<
699       b.value();
700   }
701 
702   for (size_t i = 0; i < base::size(cases); ++i) {
703     FilePath a(cases[i].inputs[0]);
704     FilePath b(cases[i].inputs[1]);
705 
706     EXPECT_EQ(a != b, !cases[i].expected) <<
707       "inequality i: " << i << ", a: " << a.value() << ", b: " <<
708       b.value();
709   }
710 }
711 
TEST_F(FilePathTest,Extension)712 TEST_F(FilePathTest, Extension) {
713   FilePath base_dir(FILE_PATH_LITERAL("base_dir"));
714 
715   FilePath jpg = base_dir.Append(FILE_PATH_LITERAL("foo.jpg"));
716   EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.Extension());
717   EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.FinalExtension());
718 
719   FilePath base = jpg.BaseName().RemoveExtension();
720   EXPECT_EQ(FILE_PATH_LITERAL("foo"), base.value());
721 
722   FilePath path_no_ext = base_dir.Append(base);
723   EXPECT_EQ(path_no_ext.value(), jpg.RemoveExtension().value());
724 
725   EXPECT_EQ(path_no_ext.value(), path_no_ext.RemoveExtension().value());
726   EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.Extension());
727   EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.FinalExtension());
728 }
729 
TEST_F(FilePathTest,Extension2)730 TEST_F(FilePathTest, Extension2) {
731   // clang-format off
732   const struct UnaryTestData cases[] = {
733 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
734     { FPL("C:\\a\\b\\c.ext"),        FPL(".ext") },
735     { FPL("C:\\a\\b\\c."),           FPL(".") },
736     { FPL("C:\\a\\b\\c"),            FPL("") },
737     { FPL("C:\\a\\b\\"),             FPL("") },
738     { FPL("C:\\a\\b.\\"),            FPL(".") },
739     { FPL("C:\\a\\b\\c.ext1.ext2"),  FPL(".ext2") },
740     { FPL("C:\\foo.bar\\\\\\"),      FPL(".bar") },
741     { FPL("C:\\foo.bar\\.."),        FPL("") },
742     { FPL("C:\\foo.bar\\..\\\\"),    FPL("") },
743 #endif
744     { FPL("/foo/bar/baz.ext"),       FPL(".ext") },
745     { FPL("/foo/bar/baz."),          FPL(".") },
746     { FPL("/foo/bar/baz.."),         FPL(".") },
747     { FPL("/foo/bar/baz"),           FPL("") },
748     { FPL("/foo/bar/"),              FPL("") },
749     { FPL("/foo/bar./"),             FPL(".") },
750     { FPL("/foo/bar/baz.ext1.ext2"), FPL(".ext2") },
751     { FPL("/subversion-1.6.12.zip"), FPL(".zip") },
752     { FPL("/foo.12345.gz"),          FPL(".gz") },
753     { FPL("/foo..gz"),               FPL(".gz") },
754     { FPL("."),                      FPL("") },
755     { FPL(".."),                     FPL("") },
756     { FPL("./foo"),                  FPL("") },
757     { FPL("./foo.ext"),              FPL(".ext") },
758     { FPL("/foo.ext1/bar.ext2"),     FPL(".ext2") },
759     { FPL("/foo.bar////"),           FPL(".bar") },
760     { FPL("/foo.bar/.."),            FPL("") },
761     { FPL("/foo.bar/..////"),        FPL("") },
762     { FPL("/foo.1234.luser.js"),     FPL(".js") },
763     { FPL("/user.js"),               FPL(".js") },
764   };
765   const struct UnaryTestData double_extension_cases[] = {
766     { FPL("/foo.tar.gz"),            FPL(".tar.gz") },
767     { FPL("/foo.tar.Z"),             FPL(".tar.Z") },
768     { FPL("/foo.tar.bz2"),           FPL(".tar.bz2") },
769     { FPL("/foo.1234.gz"),           FPL(".1234.gz") },
770     { FPL("/foo.1234.tar.gz"),       FPL(".tar.gz") },
771     { FPL("/foo.tar.tar.gz"),        FPL(".tar.gz") },
772     { FPL("/foo.tar.gz.gz"),         FPL(".gz.gz") },
773     { FPL("/foo.1234.user.js"),      FPL(".user.js") },
774     { FPL("foo.user.js"),            FPL(".user.js") },
775     { FPL("/foo.tar.bz"),            FPL(".tar.bz") },
776     { FPL("/foo.tar.xz"),            FPL(".tar.xz") },
777   };
778   // clang-format on
779 
780   for (size_t i = 0; i < base::size(cases); ++i) {
781     FilePath path(cases[i].input);
782     FilePath::StringType extension = path.Extension();
783     FilePath::StringType final_extension = path.FinalExtension();
784     EXPECT_EQ(cases[i].expected, extension)
785         << "i: " << i << ", path: " << path.value();
786     EXPECT_EQ(cases[i].expected, final_extension)
787         << "i: " << i << ", path: " << path.value();
788   }
789 
790   for (size_t i = 0; i < base::size(double_extension_cases); ++i) {
791     FilePath path(double_extension_cases[i].input);
792     FilePath::StringType extension = path.Extension();
793     EXPECT_EQ(double_extension_cases[i].expected, extension)
794         << "i: " << i << ", path: " << path.value();
795   }
796 }
797 
TEST_F(FilePathTest,InsertBeforeExtension)798 TEST_F(FilePathTest, InsertBeforeExtension) {
799   const struct BinaryTestData cases[] = {
800     { { FPL(""),                FPL("") },        FPL("") },
801     { { FPL(""),                FPL("txt") },     FPL("") },
802     { { FPL("."),               FPL("txt") },     FPL("") },
803     { { FPL(".."),              FPL("txt") },     FPL("") },
804     { { FPL("foo.dll"),         FPL("txt") },     FPL("footxt.dll") },
805     { { FPL("."),               FPL("") },        FPL(".") },
806     { { FPL("foo.dll"),         FPL(".txt") },    FPL("foo.txt.dll") },
807     { { FPL("foo"),             FPL("txt") },     FPL("footxt") },
808     { { FPL("foo"),             FPL(".txt") },    FPL("foo.txt") },
809     { { FPL("foo.baz.dll"),     FPL("txt") },     FPL("foo.baztxt.dll") },
810     { { FPL("foo.baz.dll"),     FPL(".txt") },    FPL("foo.baz.txt.dll") },
811     { { FPL("foo.dll"),         FPL("") },        FPL("foo.dll") },
812     { { FPL("foo.dll"),         FPL(".") },       FPL("foo..dll") },
813     { { FPL("foo"),             FPL("") },        FPL("foo") },
814     { { FPL("foo"),             FPL(".") },       FPL("foo.") },
815     { { FPL("foo.baz.dll"),     FPL("") },        FPL("foo.baz.dll") },
816     { { FPL("foo.baz.dll"),     FPL(".") },       FPL("foo.baz..dll") },
817 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
818     { { FPL("\\"),              FPL("") },        FPL("\\") },
819     { { FPL("\\"),              FPL("txt") },     FPL("\\txt") },
820     { { FPL("\\."),             FPL("txt") },     FPL("") },
821     { { FPL("\\.."),            FPL("txt") },     FPL("") },
822     { { FPL("\\."),             FPL("") },        FPL("\\.") },
823     { { FPL("C:\\bar\\foo.dll"), FPL("txt") },
824         FPL("C:\\bar\\footxt.dll") },
825     { { FPL("C:\\bar.baz\\foodll"), FPL("txt") },
826         FPL("C:\\bar.baz\\foodlltxt") },
827     { { FPL("C:\\bar.baz\\foo.dll"), FPL("txt") },
828         FPL("C:\\bar.baz\\footxt.dll") },
829     { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("txt") },
830         FPL("C:\\bar.baz\\foo.dlltxt.exe") },
831     { { FPL("C:\\bar.baz\\foo"), FPL("") },
832         FPL("C:\\bar.baz\\foo") },
833     { { FPL("C:\\bar.baz\\foo.exe"), FPL("") },
834         FPL("C:\\bar.baz\\foo.exe") },
835     { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("") },
836         FPL("C:\\bar.baz\\foo.dll.exe") },
837     { { FPL("C:\\bar\\baz\\foo.exe"), FPL(" (1)") },
838         FPL("C:\\bar\\baz\\foo (1).exe") },
839     { { FPL("C:\\foo.baz\\\\"), FPL(" (1)") },    FPL("C:\\foo (1).baz") },
840     { { FPL("C:\\foo.baz\\..\\"), FPL(" (1)") },  FPL("") },
841 #endif
842     { { FPL("/"),               FPL("") },        FPL("/") },
843     { { FPL("/"),               FPL("txt") },     FPL("/txt") },
844     { { FPL("/."),              FPL("txt") },     FPL("") },
845     { { FPL("/.."),             FPL("txt") },     FPL("") },
846     { { FPL("/."),              FPL("") },        FPL("/.") },
847     { { FPL("/bar/foo.dll"),    FPL("txt") },     FPL("/bar/footxt.dll") },
848     { { FPL("/bar.baz/foodll"), FPL("txt") },     FPL("/bar.baz/foodlltxt") },
849     { { FPL("/bar.baz/foo.dll"), FPL("txt") },    FPL("/bar.baz/footxt.dll") },
850     { { FPL("/bar.baz/foo.dll.exe"), FPL("txt") },
851         FPL("/bar.baz/foo.dlltxt.exe") },
852     { { FPL("/bar.baz/foo"),    FPL("") },        FPL("/bar.baz/foo") },
853     { { FPL("/bar.baz/foo.exe"), FPL("") },       FPL("/bar.baz/foo.exe") },
854     { { FPL("/bar.baz/foo.dll.exe"), FPL("") },   FPL("/bar.baz/foo.dll.exe") },
855     { { FPL("/bar/baz/foo.exe"), FPL(" (1)") },   FPL("/bar/baz/foo (1).exe") },
856     { { FPL("/bar/baz/..////"), FPL(" (1)") },    FPL("") },
857   };
858   for (unsigned int i = 0; i < base::size(cases); ++i) {
859     FilePath path(cases[i].inputs[0]);
860     FilePath result = path.InsertBeforeExtension(cases[i].inputs[1]);
861     EXPECT_EQ(cases[i].expected, result.value())
862         << "i: " << i << ", path: " << path.value()
863         << ", insert: " << cases[i].inputs[1];
864   }
865 }
866 
TEST_F(FilePathTest,RemoveExtension)867 TEST_F(FilePathTest, RemoveExtension) {
868   const struct UnaryTestData cases[] = {
869     { FPL(""),                    FPL("") },
870     { FPL("."),                   FPL(".") },
871     { FPL(".."),                  FPL("..") },
872     { FPL("foo.dll"),             FPL("foo") },
873     { FPL("./foo.dll"),           FPL("./foo") },
874     { FPL("foo..dll"),            FPL("foo.") },
875     { FPL("foo"),                 FPL("foo") },
876     { FPL("foo."),                FPL("foo") },
877     { FPL("foo.."),               FPL("foo.") },
878     { FPL("foo.baz.dll"),         FPL("foo.baz") },
879 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
880     { FPL("C:\\foo.bar\\foo"),    FPL("C:\\foo.bar\\foo") },
881     { FPL("C:\\foo.bar\\..\\\\"), FPL("C:\\foo.bar\\..\\\\") },
882 #endif
883     { FPL("/foo.bar/foo"),        FPL("/foo.bar/foo") },
884     { FPL("/foo.bar/..////"),     FPL("/foo.bar/..////") },
885   };
886   for (size_t i = 0; i < base::size(cases); ++i) {
887     FilePath path(cases[i].input);
888     FilePath removed = path.RemoveExtension();
889     FilePath removed_final = path.RemoveFinalExtension();
890     EXPECT_EQ(cases[i].expected, removed.value()) << "i: " << i <<
891         ", path: " << path.value();
892     EXPECT_EQ(cases[i].expected, removed_final.value()) << "i: " << i <<
893         ", path: " << path.value();
894   }
895 
896   const FilePath::StringPieceType tarballs[] = {
897       FPL("foo.tar.gz"), FPL("foo.tar.xz"), FPL("foo.tar.bz2"),
898       FPL("foo.tar.Z"), FPL("foo.tar.bz")};
899   for (size_t i = 0; i < base::size(tarballs); ++i) {
900     FilePath path(FPL("foo.tar.gz"));
901     FilePath removed = path.RemoveExtension();
902     FilePath removed_final = path.RemoveFinalExtension();
903     EXPECT_EQ(FPL("foo"), removed.value())
904         << "i: " << i << ", path: " << path.value();
905     EXPECT_EQ(FPL("foo.tar"), removed_final.value())
906         << "i: " << i << ", path: " << path.value();
907   }
908 }
909 
TEST_F(FilePathTest,ReplaceExtension)910 TEST_F(FilePathTest, ReplaceExtension) {
911   const struct BinaryTestData cases[] = {
912     { { FPL(""),              FPL("") },      FPL("") },
913     { { FPL(""),              FPL("txt") },   FPL("") },
914     { { FPL("."),             FPL("txt") },   FPL("") },
915     { { FPL(".."),            FPL("txt") },   FPL("") },
916     { { FPL("."),             FPL("") },      FPL("") },
917     { { FPL("foo.dll"),       FPL("txt") },   FPL("foo.txt") },
918     { { FPL("./foo.dll"),     FPL("txt") },   FPL("./foo.txt") },
919     { { FPL("foo..dll"),      FPL("txt") },   FPL("foo..txt") },
920     { { FPL("foo.dll"),       FPL(".txt") },  FPL("foo.txt") },
921     { { FPL("foo"),           FPL("txt") },   FPL("foo.txt") },
922     { { FPL("foo."),          FPL("txt") },   FPL("foo.txt") },
923     { { FPL("foo.."),         FPL("txt") },   FPL("foo..txt") },
924     { { FPL("foo"),           FPL(".txt") },  FPL("foo.txt") },
925     { { FPL("foo.baz.dll"),   FPL("txt") },   FPL("foo.baz.txt") },
926     { { FPL("foo.baz.dll"),   FPL(".txt") },  FPL("foo.baz.txt") },
927     { { FPL("foo.dll"),       FPL("") },      FPL("foo") },
928     { { FPL("foo.dll"),       FPL(".") },     FPL("foo") },
929     { { FPL("foo"),           FPL("") },      FPL("foo") },
930     { { FPL("foo"),           FPL(".") },     FPL("foo") },
931     { { FPL("foo.baz.dll"),   FPL("") },      FPL("foo.baz") },
932     { { FPL("foo.baz.dll"),   FPL(".") },     FPL("foo.baz") },
933 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
934     { { FPL("C:\\foo.bar\\foo"),    FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") },
935     { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") },
936 #endif
937     { { FPL("/foo.bar/foo"),        FPL("baz") }, FPL("/foo.bar/foo.baz") },
938     { { FPL("/foo.bar/..////"),     FPL("baz") }, FPL("") },
939   };
940   for (unsigned int i = 0; i < base::size(cases); ++i) {
941     FilePath path(cases[i].inputs[0]);
942     FilePath replaced = path.ReplaceExtension(cases[i].inputs[1]);
943     EXPECT_EQ(cases[i].expected, replaced.value()) << "i: " << i <<
944         ", path: " << path.value() << ", replace: " << cases[i].inputs[1];
945   }
946 }
947 
TEST_F(FilePathTest,AddExtension)948 TEST_F(FilePathTest, AddExtension) {
949   const struct BinaryTestData cases[] = {
950     { { FPL(""),              FPL("") },      FPL("") },
951     { { FPL(""),              FPL("txt") },   FPL("") },
952     { { FPL("."),             FPL("txt") },   FPL("") },
953     { { FPL(".."),            FPL("txt") },   FPL("") },
954     { { FPL("."),             FPL("") },      FPL("") },
955     { { FPL("foo.dll"),       FPL("txt") },   FPL("foo.dll.txt") },
956     { { FPL("./foo.dll"),     FPL("txt") },   FPL("./foo.dll.txt") },
957     { { FPL("foo..dll"),      FPL("txt") },   FPL("foo..dll.txt") },
958     { { FPL("foo.dll"),       FPL(".txt") },  FPL("foo.dll.txt") },
959     { { FPL("foo"),           FPL("txt") },   FPL("foo.txt") },
960     { { FPL("foo."),          FPL("txt") },   FPL("foo.txt") },
961     { { FPL("foo.."),         FPL("txt") },   FPL("foo..txt") },
962     { { FPL("foo"),           FPL(".txt") },  FPL("foo.txt") },
963     { { FPL("foo.baz.dll"),   FPL("txt") },   FPL("foo.baz.dll.txt") },
964     { { FPL("foo.baz.dll"),   FPL(".txt") },  FPL("foo.baz.dll.txt") },
965     { { FPL("foo.dll"),       FPL("") },      FPL("foo.dll") },
966     { { FPL("foo.dll"),       FPL(".") },     FPL("foo.dll") },
967     { { FPL("foo"),           FPL("") },      FPL("foo") },
968     { { FPL("foo"),           FPL(".") },     FPL("foo") },
969     { { FPL("foo.baz.dll"),   FPL("") },      FPL("foo.baz.dll") },
970     { { FPL("foo.baz.dll"),   FPL(".") },     FPL("foo.baz.dll") },
971 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
972     { { FPL("C:\\foo.bar\\foo"),    FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") },
973     { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") },
974 #endif
975     { { FPL("/foo.bar/foo"),        FPL("baz") }, FPL("/foo.bar/foo.baz") },
976     { { FPL("/foo.bar/..////"),     FPL("baz") }, FPL("") },
977   };
978   for (unsigned int i = 0; i < base::size(cases); ++i) {
979     FilePath path(cases[i].inputs[0]);
980     FilePath added = path.AddExtension(cases[i].inputs[1]);
981     EXPECT_EQ(cases[i].expected, added.value()) << "i: " << i <<
982         ", path: " << path.value() << ", add: " << cases[i].inputs[1];
983   }
984 }
985 
TEST_F(FilePathTest,MatchesExtension)986 TEST_F(FilePathTest, MatchesExtension) {
987   const struct BinaryBooleanTestData cases[] = {
988     { { FPL("foo"),                     FPL("") },                    true},
989     { { FPL("foo"),                     FPL(".") },                   false},
990     { { FPL("foo."),                    FPL("") },                    false},
991     { { FPL("foo."),                    FPL(".") },                   true},
992     { { FPL("foo.txt"),                 FPL(".dll") },                false},
993     { { FPL("foo.txt"),                 FPL(".txt") },                true},
994     { { FPL("foo.txt.dll"),             FPL(".txt") },                false},
995     { { FPL("foo.txt.dll"),             FPL(".dll") },                true},
996     { { FPL("foo.TXT"),                 FPL(".txt") },                true},
997     { { FPL("foo.txt"),                 FPL(".TXT") },                true},
998     { { FPL("foo.tXt"),                 FPL(".txt") },                true},
999     { { FPL("foo.txt"),                 FPL(".tXt") },                true},
1000     { { FPL("foo.tXt"),                 FPL(".TXT") },                true},
1001     { { FPL("foo.tXt"),                 FPL(".tXt") },                true},
1002 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
1003     { { FPL("c:/foo.txt.dll"),          FPL(".txt") },                false},
1004     { { FPL("c:/foo.txt"),              FPL(".txt") },                true},
1005 #endif  // FILE_PATH_USES_DRIVE_LETTERS
1006 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
1007     { { FPL("c:\\bar\\foo.txt.dll"),    FPL(".txt") },                false},
1008     { { FPL("c:\\bar\\foo.txt"),        FPL(".txt") },                true},
1009 #endif  // FILE_PATH_USES_DRIVE_LETTERS
1010     { { FPL("/bar/foo.txt.dll"),        FPL(".txt") },                false},
1011     { { FPL("/bar/foo.txt"),            FPL(".txt") },                true},
1012 #if defined(OS_WIN) || defined(OS_MACOSX)
1013     // Umlauts A, O, U: direct comparison, and upper case vs. lower case
1014     { { FPL("foo.\u00E4\u00F6\u00FC"),  FPL(".\u00E4\u00F6\u00FC") }, true},
1015     { { FPL("foo.\u00C4\u00D6\u00DC"),  FPL(".\u00E4\u00F6\u00FC") }, true},
1016     // C with circumflex: direct comparison, and upper case vs. lower case
1017     { { FPL("foo.\u0109"),              FPL(".\u0109") },             true},
1018     { { FPL("foo.\u0108"),              FPL(".\u0109") },             true},
1019 #endif
1020   };
1021 
1022   for (size_t i = 0; i < base::size(cases); ++i) {
1023     FilePath path(cases[i].inputs[0]);
1024     FilePath::StringType ext(cases[i].inputs[1]);
1025 
1026     EXPECT_EQ(cases[i].expected, path.MatchesExtension(ext)) <<
1027         "i: " << i << ", path: " << path.value() << ", ext: " << ext;
1028   }
1029 }
1030 
TEST_F(FilePathTest,CompareIgnoreCase)1031 TEST_F(FilePathTest, CompareIgnoreCase) {
1032   const struct BinaryIntTestData cases[] = {
1033     { { FPL("foo"),                          FPL("foo") },                  0},
1034     { { FPL("FOO"),                          FPL("foo") },                  0},
1035     { { FPL("foo.ext"),                      FPL("foo.ext") },              0},
1036     { { FPL("FOO.EXT"),                      FPL("foo.ext") },              0},
1037     { { FPL("Foo.Ext"),                      FPL("foo.ext") },              0},
1038     { { FPL("foO"),                          FPL("foo") },                  0},
1039     { { FPL("foo"),                          FPL("foO") },                  0},
1040     { { FPL("fOo"),                          FPL("foo") },                  0},
1041     { { FPL("foo"),                          FPL("fOo") },                  0},
1042     { { FPL("bar"),                          FPL("foo") },                 -1},
1043     { { FPL("foo"),                          FPL("bar") },                  1},
1044     { { FPL("BAR"),                          FPL("foo") },                 -1},
1045     { { FPL("FOO"),                          FPL("bar") },                  1},
1046     { { FPL("bar"),                          FPL("FOO") },                 -1},
1047     { { FPL("foo"),                          FPL("BAR") },                  1},
1048     { { FPL("BAR"),                          FPL("FOO") },                 -1},
1049     { { FPL("FOO"),                          FPL("BAR") },                  1},
1050     // German "Eszett" (lower case and the new-fangled upper case)
1051     // Note that uc(<lowercase eszett>) => "SS", NOT <uppercase eszett>!
1052     // However, neither Windows nor Mac OSX converts these.
1053     // (or even have glyphs for <uppercase eszett>)
1054     { { FPL("\u00DF"),                       FPL("\u00DF") },               0},
1055     { { FPL("\u1E9E"),                       FPL("\u1E9E") },               0},
1056     { { FPL("\u00DF"),                       FPL("\u1E9E") },              -1},
1057     { { FPL("SS"),                           FPL("\u00DF") },              -1},
1058     { { FPL("SS"),                           FPL("\u1E9E") },              -1},
1059 #if defined(OS_WIN) || defined(OS_MACOSX)
1060     // Umlauts A, O, U: direct comparison, and upper case vs. lower case
1061     { { FPL("\u00E4\u00F6\u00FC"),           FPL("\u00E4\u00F6\u00FC") },   0},
1062     { { FPL("\u00C4\u00D6\u00DC"),           FPL("\u00E4\u00F6\u00FC") },   0},
1063     // C with circumflex: direct comparison, and upper case vs. lower case
1064     { { FPL("\u0109"),                       FPL("\u0109") },               0},
1065     { { FPL("\u0108"),                       FPL("\u0109") },               0},
1066     // Cyrillic letter SHA: direct comparison, and upper case vs. lower case
1067     { { FPL("\u0428"),                       FPL("\u0428") },               0},
1068     { { FPL("\u0428"),                       FPL("\u0448") },               0},
1069     // Greek letter DELTA: direct comparison, and upper case vs. lower case
1070     { { FPL("\u0394"),                       FPL("\u0394") },               0},
1071     { { FPL("\u0394"),                       FPL("\u03B4") },               0},
1072     // Japanese full-width A: direct comparison, and upper case vs. lower case
1073     // Note that full-width and standard characters are considered different.
1074     { { FPL("\uFF21"),                       FPL("\uFF21") },               0},
1075     { { FPL("\uFF21"),                       FPL("\uFF41") },               0},
1076     { { FPL("A"),                            FPL("\uFF21") },              -1},
1077     { { FPL("A"),                            FPL("\uFF41") },              -1},
1078     { { FPL("a"),                            FPL("\uFF21") },              -1},
1079     { { FPL("a"),                            FPL("\uFF41") },              -1},
1080 #endif
1081 #if defined(OS_MACOSX)
1082     // Codepoints > 0x1000
1083     // Georgian letter DON: direct comparison, and upper case vs. lower case
1084     { { FPL("\u10A3"),                       FPL("\u10A3") },               0},
1085     { { FPL("\u10A3"),                       FPL("\u10D3") },               0},
1086     // Combining characters vs. pre-composed characters, upper and lower case
1087     { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E31\u1E77\u1E53n") },  0},
1088     { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("kuon") },                 1},
1089     { { FPL("kuon"), FPL("k\u0301u\u032Do\u0304\u0301n") },                -1},
1090     { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("KUON") },                 1},
1091     { { FPL("KUON"), FPL("K\u0301U\u032DO\u0304\u0301N") },                -1},
1092     { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("KUON") },                 1},
1093     { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("\u1E31\u1E77\u1E53n") },  0},
1094     { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E30\u1E76\u1E52n") },  0},
1095     { { FPL("k\u0301u\u032Do\u0304\u0302n"), FPL("\u1E30\u1E76\u1E52n") },  1},
1096 #endif
1097   };
1098 
1099   for (size_t i = 0; i < base::size(cases); ++i) {
1100     FilePath::StringType s1(cases[i].inputs[0]);
1101     FilePath::StringType s2(cases[i].inputs[1]);
1102     int result = FilePath::CompareIgnoreCase(s1, s2);
1103     EXPECT_EQ(cases[i].expected, result) <<
1104         "i: " << i << ", s1: " << s1 << ", s2: " << s2;
1105   }
1106 }
1107 
TEST_F(FilePathTest,ReferencesParent)1108 TEST_F(FilePathTest, ReferencesParent) {
1109   const struct UnaryBooleanTestData cases[] = {
1110     { FPL("."),        false },
1111     { FPL(".."),       true },
1112     { FPL(".. "),      true },
1113     { FPL(" .."),      true },
1114     { FPL("..."),      true },
1115     { FPL("a.."),      false },
1116     { FPL("..a"),      false },
1117     { FPL("../"),      true },
1118     { FPL("/.."),      true },
1119     { FPL("/../"),     true },
1120     { FPL("/a../"),    false },
1121     { FPL("/..a/"),    false },
1122     { FPL("//.."),     true },
1123     { FPL("..//"),     true },
1124     { FPL("//..//"),   true },
1125     { FPL("a//..//c"), true },
1126     { FPL("../b/c"),   true },
1127     { FPL("/../b/c"),  true },
1128     { FPL("a/b/.."),   true },
1129     { FPL("a/b/../"),  true },
1130     { FPL("a/../c"),   true },
1131     { FPL("a/b/c"),    false },
1132   };
1133 
1134   for (size_t i = 0; i < base::size(cases); ++i) {
1135     FilePath input(cases[i].input);
1136     bool observed = input.ReferencesParent();
1137     EXPECT_EQ(cases[i].expected, observed) <<
1138               "i: " << i << ", input: " << input.value();
1139   }
1140 }
1141 
TEST_F(FilePathTest,FromUTF8Unsafe_And_AsUTF8Unsafe)1142 TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) {
1143   const struct UTF8TestData cases[] = {
1144     { FPL("foo.txt"), "foo.txt" },
1145     // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them.
1146     { FPL("\u00E0\u00E8\u00F2.txt"), "\xC3\xA0\xC3\xA8\xC3\xB2.txt" },
1147     // Full-width "ABC".
1148     { FPL("\uFF21\uFF22\uFF23.txt"),
1149       "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3.txt" },
1150   };
1151 
1152 #if !defined(SYSTEM_NATIVE_UTF8) && defined(OS_LINUX)
1153   ScopedLocale locale("en_US.UTF-8");
1154 #endif
1155 
1156   for (size_t i = 0; i < base::size(cases); ++i) {
1157     // Test FromUTF8Unsafe() works.
1158     FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8);
1159     EXPECT_EQ(cases[i].native, from_utf8.value())
1160         << "i: " << i << ", input: " << cases[i].native;
1161     // Test AsUTF8Unsafe() works.
1162     FilePath from_native = FilePath(cases[i].native);
1163     EXPECT_EQ(cases[i].utf8, from_native.AsUTF8Unsafe())
1164         << "i: " << i << ", input: " << cases[i].native;
1165     // Test the two file paths are identical.
1166     EXPECT_EQ(from_utf8.value(), from_native.value());
1167   }
1168 }
1169 
TEST_F(FilePathTest,ConstructWithNUL)1170 TEST_F(FilePathTest, ConstructWithNUL) {
1171   // Assert FPS() works.
1172   ASSERT_EQ(3U, FPS("a\0b").length());
1173 
1174   // Test constructor strips '\0'
1175   FilePath path(FPS("a\0b"));
1176   EXPECT_EQ(1U, path.value().length());
1177   EXPECT_EQ(FPL("a"), path.value());
1178 }
1179 
TEST_F(FilePathTest,AppendWithNUL)1180 TEST_F(FilePathTest, AppendWithNUL) {
1181   // Assert FPS() works.
1182   ASSERT_EQ(3U, FPS("b\0b").length());
1183 
1184   // Test Append() strips '\0'
1185   FilePath path(FPL("a"));
1186   path = path.Append(FPS("b\0b"));
1187   EXPECT_EQ(3U, path.value().length());
1188 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
1189   EXPECT_EQ(FPL("a\\b"), path.value());
1190 #else
1191   EXPECT_EQ(FPL("a/b"), path.value());
1192 #endif
1193 }
1194 
TEST_F(FilePathTest,ReferencesParentWithNUL)1195 TEST_F(FilePathTest, ReferencesParentWithNUL) {
1196   // Assert FPS() works.
1197   ASSERT_EQ(3U, FPS("..\0").length());
1198 
1199   // Test ReferencesParent() doesn't break with "..\0"
1200   FilePath path(FPS("..\0"));
1201   EXPECT_TRUE(path.ReferencesParent());
1202 }
1203 
1204 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
TEST_F(FilePathTest,NormalizePathSeparators)1205 TEST_F(FilePathTest, NormalizePathSeparators) {
1206   const struct UnaryTestData cases[] = {
1207     { FPL("foo/bar"), FPL("foo\\bar") },
1208     { FPL("foo/bar\\betz"), FPL("foo\\bar\\betz") },
1209     { FPL("foo\\bar"), FPL("foo\\bar") },
1210     { FPL("foo\\bar/betz"), FPL("foo\\bar\\betz") },
1211     { FPL("foo"), FPL("foo") },
1212     // Trailing slashes don't automatically get stripped.  That's what
1213     // StripTrailingSeparators() is for.
1214     { FPL("foo\\"), FPL("foo\\") },
1215     { FPL("foo/"), FPL("foo\\") },
1216     { FPL("foo/bar\\"), FPL("foo\\bar\\") },
1217     { FPL("foo\\bar/"), FPL("foo\\bar\\") },
1218     { FPL("foo/bar/"), FPL("foo\\bar\\") },
1219     { FPL("foo\\bar\\"), FPL("foo\\bar\\") },
1220     { FPL("\\foo/bar"), FPL("\\foo\\bar") },
1221     { FPL("/foo\\bar"), FPL("\\foo\\bar") },
1222     { FPL("c:/foo/bar/"), FPL("c:\\foo\\bar\\") },
1223     { FPL("/foo/bar/"), FPL("\\foo\\bar\\") },
1224     { FPL("\\foo\\bar\\"), FPL("\\foo\\bar\\") },
1225     { FPL("c:\\foo/bar"), FPL("c:\\foo\\bar") },
1226     { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
1227     { FPL("\\\\foo\\bar\\"), FPL("\\\\foo\\bar\\") },
1228     { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
1229     // This method does not normalize the number of path separators.
1230     { FPL("foo\\\\bar"), FPL("foo\\\\bar") },
1231     { FPL("foo//bar"), FPL("foo\\\\bar") },
1232     { FPL("foo/\\bar"), FPL("foo\\\\bar") },
1233     { FPL("foo\\/bar"), FPL("foo\\\\bar") },
1234     { FPL("///foo\\\\bar"), FPL("\\\\\\foo\\\\bar") },
1235     { FPL("foo//bar///"), FPL("foo\\\\bar\\\\\\") },
1236     { FPL("foo/\\bar/\\"), FPL("foo\\\\bar\\\\") },
1237     { FPL("/\\foo\\/bar"), FPL("\\\\foo\\\\bar") },
1238   };
1239   for (size_t i = 0; i < base::size(cases); ++i) {
1240     FilePath input(cases[i].input);
1241     FilePath observed = input.NormalizePathSeparators();
1242     EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
1243               "i: " << i << ", input: " << input.value();
1244   }
1245 }
1246 #endif
1247 
TEST_F(FilePathTest,EndsWithSeparator)1248 TEST_F(FilePathTest, EndsWithSeparator) {
1249   const UnaryBooleanTestData cases[] = {
1250     { FPL(""), false },
1251     { FPL("/"), true },
1252     { FPL("foo/"), true },
1253     { FPL("bar"), false },
1254     { FPL("/foo/bar"), false },
1255   };
1256   for (const auto& i : cases) {
1257     FilePath input = FilePath(i.input).NormalizePathSeparators();
1258     EXPECT_EQ(i.expected, input.EndsWithSeparator());
1259   }
1260 }
1261 
TEST_F(FilePathTest,AsEndingWithSeparator)1262 TEST_F(FilePathTest, AsEndingWithSeparator) {
1263   const UnaryTestData cases[] = {
1264     { FPL(""), FPL("") },
1265     { FPL("/"), FPL("/") },
1266     { FPL("foo"), FPL("foo/") },
1267     { FPL("foo/"), FPL("foo/") }
1268   };
1269   for (const auto& i : cases) {
1270     FilePath input = FilePath(i.input).NormalizePathSeparators();
1271     FilePath expected = FilePath(i.expected).NormalizePathSeparators();
1272     EXPECT_EQ(expected.value(), input.AsEndingWithSeparator().value());
1273   }
1274 }
1275 
1276 #if defined(OS_ANDROID)
TEST_F(FilePathTest,ContentUriTest)1277 TEST_F(FilePathTest, ContentUriTest) {
1278   const struct UnaryBooleanTestData cases[] = {
1279     { FPL("content://foo.bar"),    true },
1280     { FPL("content://foo.bar/"),   true },
1281     { FPL("content://foo/bar"),    true },
1282     { FPL("CoNTenT://foo.bar"),    true },
1283     { FPL("content://"),           true },
1284     { FPL("content:///foo.bar"),   true },
1285     { FPL("content://3foo/bar"),   true },
1286     { FPL("content://_foo/bar"),   true },
1287     { FPL(".. "),                  false },
1288     { FPL("foo.bar"),              false },
1289     { FPL("content:foo.bar"),      false },
1290     { FPL("content:/foo.ba"),      false },
1291     { FPL("content:/dir/foo.bar"), false },
1292     { FPL("content: //foo.bar"),   false },
1293     { FPL("content%2a%2f%2f"),     false },
1294   };
1295 
1296   for (size_t i = 0; i < base::size(cases); ++i) {
1297     FilePath input(cases[i].input);
1298     bool observed = input.IsContentUri();
1299     EXPECT_EQ(cases[i].expected, observed) <<
1300               "i: " << i << ", input: " << input.value();
1301   }
1302 }
1303 #endif
1304 
1305 // Test the operator<<(ostream, FilePath).
TEST_F(FilePathTest,PrintToOstream)1306 TEST_F(FilePathTest, PrintToOstream) {
1307   std::stringstream ss;
1308   FilePath fp(FPL("foo"));
1309   ss << fp;
1310   EXPECT_EQ("foo", ss.str());
1311 }
1312 
1313 // Test GetHFSDecomposedForm should return empty result for invalid UTF-8
1314 // strings.
1315 #if defined(OS_MACOSX)
TEST_F(FilePathTest,GetHFSDecomposedFormWithInvalidInput)1316 TEST_F(FilePathTest, GetHFSDecomposedFormWithInvalidInput) {
1317   const FilePath::CharType* cases[] = {
1318     FPL("\xc3\x28"),
1319     FPL("\xe2\x82\x28"),
1320     FPL("\xe2\x28\xa1"),
1321     FPL("\xf0\x28\x8c\xbc"),
1322     FPL("\xf0\x28\x8c\x28"),
1323   };
1324   for (auto* invalid_input : cases) {
1325     FilePath::StringType observed = FilePath::GetHFSDecomposedForm(
1326         invalid_input);
1327     EXPECT_TRUE(observed.empty());
1328   }
1329 }
1330 
TEST_F(FilePathTest,CompareIgnoreCaseWithInvalidInput)1331 TEST_F(FilePathTest, CompareIgnoreCaseWithInvalidInput) {
1332   const FilePath::CharType* cases[] = {
1333       FPL("\xc3\x28"),         FPL("\xe2\x82\x28"),     FPL("\xe2\x28\xa1"),
1334       FPL("\xf0\x28\x8c\xbc"), FPL("\xf0\x28\x8c\x28"),
1335   };
1336   for (auto* invalid_input : cases) {
1337     // All example inputs will be greater than the string "fixed".
1338     EXPECT_EQ(FilePath::CompareIgnoreCase(invalid_input, FPL("fixed")), 1);
1339   }
1340 }
1341 #endif
1342 
1343 }  // namespace base
1344