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