1 //===-- FileSpecTest.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "gtest/gtest.h"
11 
12 #include "lldb/Utility/FileSpec.h"
13 
14 using namespace lldb_private;
15 
16 TEST(FileSpecTest, FileAndDirectoryComponents) {
17   FileSpec fs_posix("/foo/bar", false, FileSpec::ePathSyntaxPosix);
18   EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
19   EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
20   EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
21 
22   FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
23   EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
24   // EXPECT_STREQ("F:\\", fs_windows.GetDirectory().GetCString()); // It returns
25   // "F:/"
26   EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
27 
28   FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
29   EXPECT_STREQ("/", fs_posix_root.GetCString());
30   EXPECT_EQ(nullptr, fs_posix_root.GetDirectory().GetCString());
31   EXPECT_STREQ("/", fs_posix_root.GetFilename().GetCString());
32 
33   FileSpec fs_windows_drive("F:", false, FileSpec::ePathSyntaxWindows);
34   EXPECT_STREQ("F:", fs_windows_drive.GetCString());
35   EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString());
36   EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString());
37 
38   FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
39   EXPECT_STREQ("F:\\", fs_windows_root.GetCString());
40   EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
41   // EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString()); // It
42   // returns "/"
43 
44   FileSpec fs_posix_long("/foo/bar/baz", false, FileSpec::ePathSyntaxPosix);
45   EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString());
46   EXPECT_STREQ("/foo/bar", fs_posix_long.GetDirectory().GetCString());
47   EXPECT_STREQ("baz", fs_posix_long.GetFilename().GetCString());
48 
49   FileSpec fs_windows_long("F:\\bar\\baz", false, FileSpec::ePathSyntaxWindows);
50   EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString());
51   // EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString()); // It
52   // returns "F:/bar"
53   EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString());
54 
55   FileSpec fs_posix_trailing_slash("/foo/bar/", false,
56                                    FileSpec::ePathSyntaxPosix);
57   EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetCString());
58   EXPECT_STREQ("/foo", fs_posix_trailing_slash.GetDirectory().GetCString());
59   EXPECT_STREQ("bar", fs_posix_trailing_slash.GetFilename().GetCString());
60 
61   FileSpec fs_windows_trailing_slash("F:\\bar\\", false,
62                                      FileSpec::ePathSyntaxWindows);
63   EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetCString());
64   EXPECT_STREQ("bar", fs_windows_trailing_slash.GetFilename().GetCString());
65 }
66 
67 TEST(FileSpecTest, AppendPathComponent) {
68   FileSpec fs_posix("/foo", false, FileSpec::ePathSyntaxPosix);
69   fs_posix.AppendPathComponent("bar");
70   EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
71   EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
72   EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
73 
74   FileSpec fs_posix_2("/foo", false, FileSpec::ePathSyntaxPosix);
75   fs_posix_2.AppendPathComponent("//bar/baz");
76   EXPECT_STREQ("/foo/bar/baz", fs_posix_2.GetCString());
77   EXPECT_STREQ("/foo/bar", fs_posix_2.GetDirectory().GetCString());
78   EXPECT_STREQ("baz", fs_posix_2.GetFilename().GetCString());
79 
80   FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
81   fs_windows.AppendPathComponent("baz");
82   EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
83   // EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It
84   // returns "F:/bar"
85   EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
86 
87   FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
88   fs_posix_root.AppendPathComponent("bar");
89   EXPECT_STREQ("/bar", fs_posix_root.GetCString());
90   EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
91   EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
92 
93   FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
94   fs_windows_root.AppendPathComponent("bar");
95   EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
96   // EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It
97   // returns "F:/"
98   EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
99 }
100 
101 TEST(FileSpecTest, CopyByAppendingPathComponent) {
102   FileSpec fs = FileSpec("/foo", false, FileSpec::ePathSyntaxPosix)
103                     .CopyByAppendingPathComponent("bar");
104   EXPECT_STREQ("/foo/bar", fs.GetCString());
105   EXPECT_STREQ("/foo", fs.GetDirectory().GetCString());
106   EXPECT_STREQ("bar", fs.GetFilename().GetCString());
107 }
108 
109 TEST(FileSpecTest, PrependPathComponent) {
110   FileSpec fs_posix("foo", false, FileSpec::ePathSyntaxPosix);
111   fs_posix.PrependPathComponent("/bar");
112   EXPECT_STREQ("/bar/foo", fs_posix.GetCString());
113 
114   FileSpec fs_posix_2("foo/bar", false, FileSpec::ePathSyntaxPosix);
115   fs_posix_2.PrependPathComponent("/baz");
116   EXPECT_STREQ("/baz/foo/bar", fs_posix_2.GetCString());
117 
118   FileSpec fs_windows("baz", false, FileSpec::ePathSyntaxWindows);
119   fs_windows.PrependPathComponent("F:\\bar");
120   EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
121 
122   FileSpec fs_posix_root("bar", false, FileSpec::ePathSyntaxPosix);
123   fs_posix_root.PrependPathComponent("/");
124   EXPECT_STREQ("/bar", fs_posix_root.GetCString());
125 
126   FileSpec fs_windows_root("bar", false, FileSpec::ePathSyntaxWindows);
127   fs_windows_root.PrependPathComponent("F:\\");
128   EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
129 }
130 
131 TEST(FileSpecTest, EqualSeparator) {
132   FileSpec backward("C:\\foo\\bar", false, FileSpec::ePathSyntaxWindows);
133   FileSpec forward("C:/foo/bar", false, FileSpec::ePathSyntaxWindows);
134   EXPECT_EQ(forward, backward);
135 }
136 
137 TEST(FileSpecTest, EqualDotsWindows) {
138   std::pair<const char *, const char *> tests[] = {
139       {R"(C:\foo\bar\baz)", R"(C:\foo\foo\..\bar\baz)"},
140       {R"(C:\bar\baz)", R"(C:\foo\..\bar\baz)"},
141       {R"(C:\bar\baz)", R"(C:/foo/../bar/baz)"},
142       {R"(C:/bar/baz)", R"(C:\foo\..\bar\baz)"},
143       {R"(C:\bar)", R"(C:\foo\..\bar)"},
144       {R"(C:\foo\bar)", R"(C:\foo\.\bar)"},
145       {R"(C:\foo\bar)", R"(C:\foo\bar\.)"},
146   };
147 
148   for (const auto &test : tests) {
149     FileSpec one(test.first, false, FileSpec::ePathSyntaxWindows);
150     FileSpec two(test.second, false, FileSpec::ePathSyntaxWindows);
151     EXPECT_EQ(one, two);
152   }
153 }
154 
155 TEST(FileSpecTest, EqualDotsPosix) {
156   std::pair<const char *, const char *> tests[] = {
157       {R"(/foo/bar/baz)", R"(/foo/foo/../bar/baz)"},
158       {R"(/bar/baz)", R"(/foo/../bar/baz)"},
159       {R"(/bar)", R"(/foo/../bar)"},
160       {R"(/foo/bar)", R"(/foo/./bar)"},
161       {R"(/foo/bar)", R"(/foo/bar/.)"},
162   };
163 
164   for (const auto &test : tests) {
165     FileSpec one(test.first, false, FileSpec::ePathSyntaxPosix);
166     FileSpec two(test.second, false, FileSpec::ePathSyntaxPosix);
167     EXPECT_EQ(one, two);
168   }
169 }
170 
171 TEST(FileSpecTest, EqualDotsPosixRoot) {
172   std::pair<const char *, const char *> tests[] = {
173       {R"(/)", R"(/..)"},
174       {R"(/)", R"(/.)"},
175       {R"(/)", R"(/foo/..)"},
176   };
177 
178   for (const auto &test : tests) {
179     FileSpec one(test.first, false, FileSpec::ePathSyntaxPosix);
180     FileSpec two(test.second, false, FileSpec::ePathSyntaxPosix);
181     EXPECT_EQ(one, two);
182   }
183 }
184 
185 TEST(FileSpecTest, GetNormalizedPath) {
186   std::pair<const char *, const char *> posix_tests[] = {
187       {"/foo/.././bar", "/bar"},
188       {"/foo/./../bar", "/bar"},
189       {"/foo/../bar", "/bar"},
190       {"/foo/./bar", "/foo/bar"},
191       {"/foo/..", "/"},
192       {"/foo/.", "/foo"},
193       {"/foo//bar", "/foo/bar"},
194       {"/foo//bar/baz", "/foo/bar/baz"},
195       {"/foo//bar/./baz", "/foo/bar/baz"},
196       {"/./foo", "/foo"},
197       {"/", "/"},
198       // TODO: fix llvm::sys::path::remove_dots() to return "//" below.
199       //{"//", "//"},
200       {"//net", "//net"},
201       {"/..", "/"},
202       {"/.", "/"},
203       {"..", ".."},
204       {".", ""},
205       {"../..", "../.."},
206       {"foo/..", ""},
207       {"foo/../bar", "bar"},
208       {"../foo/..", ".."},
209       {"./foo", "foo"},
210       {"././foo", "foo"},
211       {"../foo", "../foo"},
212       {"../../foo", "../../foo"},
213   };
214   for (auto test : posix_tests) {
215     EXPECT_EQ(test.second,
216               FileSpec(test.first, false, FileSpec::ePathSyntaxPosix)
217                   .GetPath());
218   }
219 
220   std::pair<const char *, const char *> windows_tests[] = {
221       {R"(c:\bar\..\bar)", R"(c:\bar)"},
222       {R"(c:\bar\.\bar)", R"(c:\bar\bar)"},
223       {R"(c:\bar\..)", R"(c:\)"},
224       {R"(c:\bar\.)", R"(c:\bar)"},
225       {R"(c:\.\bar)", R"(c:\bar)"},
226       {R"(\)", R"(\)"},
227       //      {R"(\\)", R"(\\)"},
228       //      {R"(\\net)", R"(\\net)"},
229       {R"(c:\..)", R"(c:\)"},
230       {R"(c:\.)", R"(c:\)"},
231       // TODO: fix llvm::sys::path::remove_dots() to return "\" below.
232       {R"(\..)", R"(\..)"},
233       //      {R"(c:..)", R"(c:..)"},
234       {R"(..)", R"(..)"},
235       {R"(.)", R"()"},
236       // TODO: fix llvm::sys::path::remove_dots() to return "c:\" below.
237       {R"(c:..\..)", R"(c:\..\..)"},
238       {R"(..\..)", R"(..\..)"},
239       {R"(foo\..)", R"()"},
240       {R"(foo\..\bar)", R"(bar)"},
241       {R"(..\foo\..)", R"(..)"},
242       {R"(.\foo)", R"(foo)"},
243       {R"(.\.\foo)", R"(foo)"},
244       {R"(..\foo)", R"(..\foo)"},
245       {R"(..\..\foo)", R"(..\..\foo)"},
246   };
247   for (auto test : windows_tests) {
248     EXPECT_EQ(test.second,
249               FileSpec(test.first, false, FileSpec::ePathSyntaxWindows)
250                   .GetPath())
251         << "Original path: " << test.first;
252   }
253 }
254 
255 TEST(FileSpecTest, FormatFileSpec) {
256   auto win = FileSpec::ePathSyntaxWindows;
257 
258   FileSpec F;
259   EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str());
260   EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
261   EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str());
262 
263   F = FileSpec("C:\\foo\\bar.txt", false, win);
264   EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str());
265   EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str());
266   EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
267 
268   F = FileSpec("foo\\bar.txt", false, win);
269   EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str());
270   EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str());
271   EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
272 
273   F = FileSpec("foo", false, win);
274   EXPECT_EQ("foo", llvm::formatv("{0}", F).str());
275   EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str());
276   EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
277 }
278 
279