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::Style::posix);
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::Style::windows);
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::Style::posix);
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::Style::windows);
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::Style::windows);
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::Style::posix);
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::Style::windows);
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, FileSpec::Style::posix);
56   EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetCString());
57   EXPECT_STREQ("/foo", fs_posix_trailing_slash.GetDirectory().GetCString());
58   EXPECT_STREQ("bar", fs_posix_trailing_slash.GetFilename().GetCString());
59 
60   FileSpec fs_windows_trailing_slash("F:\\bar\\", false,
61                                      FileSpec::Style::windows);
62   EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetCString());
63   EXPECT_STREQ("bar", fs_windows_trailing_slash.GetFilename().GetCString());
64 }
65 
66 TEST(FileSpecTest, AppendPathComponent) {
67   FileSpec fs_posix("/foo", false, FileSpec::Style::posix);
68   fs_posix.AppendPathComponent("bar");
69   EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
70   EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
71   EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
72 
73   FileSpec fs_posix_2("/foo", false, FileSpec::Style::posix);
74   fs_posix_2.AppendPathComponent("//bar/baz");
75   EXPECT_STREQ("/foo/bar/baz", fs_posix_2.GetCString());
76   EXPECT_STREQ("/foo/bar", fs_posix_2.GetDirectory().GetCString());
77   EXPECT_STREQ("baz", fs_posix_2.GetFilename().GetCString());
78 
79   FileSpec fs_windows("F:\\bar", false, FileSpec::Style::windows);
80   fs_windows.AppendPathComponent("baz");
81   EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
82   // EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It
83   // returns "F:/bar"
84   EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
85 
86   FileSpec fs_posix_root("/", false, FileSpec::Style::posix);
87   fs_posix_root.AppendPathComponent("bar");
88   EXPECT_STREQ("/bar", fs_posix_root.GetCString());
89   EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
90   EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
91 
92   FileSpec fs_windows_root("F:\\", false, FileSpec::Style::windows);
93   fs_windows_root.AppendPathComponent("bar");
94   EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
95   // EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It
96   // returns "F:/"
97   EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
98 }
99 
100 TEST(FileSpecTest, CopyByAppendingPathComponent) {
101   FileSpec fs = FileSpec("/foo", false, FileSpec::Style::posix)
102                     .CopyByAppendingPathComponent("bar");
103   EXPECT_STREQ("/foo/bar", fs.GetCString());
104   EXPECT_STREQ("/foo", fs.GetDirectory().GetCString());
105   EXPECT_STREQ("bar", fs.GetFilename().GetCString());
106 }
107 
108 TEST(FileSpecTest, PrependPathComponent) {
109   FileSpec fs_posix("foo", false, FileSpec::Style::posix);
110   fs_posix.PrependPathComponent("/bar");
111   EXPECT_STREQ("/bar/foo", fs_posix.GetCString());
112 
113   FileSpec fs_posix_2("foo/bar", false, FileSpec::Style::posix);
114   fs_posix_2.PrependPathComponent("/baz");
115   EXPECT_STREQ("/baz/foo/bar", fs_posix_2.GetCString());
116 
117   FileSpec fs_windows("baz", false, FileSpec::Style::windows);
118   fs_windows.PrependPathComponent("F:\\bar");
119   EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
120 
121   FileSpec fs_posix_root("bar", false, FileSpec::Style::posix);
122   fs_posix_root.PrependPathComponent("/");
123   EXPECT_STREQ("/bar", fs_posix_root.GetCString());
124 
125   FileSpec fs_windows_root("bar", false, FileSpec::Style::windows);
126   fs_windows_root.PrependPathComponent("F:\\");
127   EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
128 }
129 
130 TEST(FileSpecTest, EqualSeparator) {
131   FileSpec backward("C:\\foo\\bar", false, FileSpec::Style::windows);
132   FileSpec forward("C:/foo/bar", false, FileSpec::Style::windows);
133   EXPECT_EQ(forward, backward);
134 }
135 
136 TEST(FileSpecTest, EqualDotsWindows) {
137   std::pair<const char *, const char *> tests[] = {
138       {R"(C:\foo\bar\baz)", R"(C:\foo\foo\..\bar\baz)"},
139       {R"(C:\bar\baz)", R"(C:\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)", R"(C:\foo\..\bar)"},
143       {R"(C:\foo\bar)", R"(C:\foo\.\bar)"},
144       {R"(C:\foo\bar)", R"(C:\foo\bar\.)"},
145   };
146 
147   for (const auto &test : tests) {
148     FileSpec one(test.first, false, FileSpec::Style::windows);
149     FileSpec two(test.second, false, FileSpec::Style::windows);
150     EXPECT_EQ(one, two);
151   }
152 }
153 
154 TEST(FileSpecTest, EqualDotsPosix) {
155   std::pair<const char *, const char *> tests[] = {
156       {R"(/foo/bar/baz)", R"(/foo/foo/../bar/baz)"},
157       {R"(/bar/baz)", R"(/foo/../bar/baz)"},
158       {R"(/bar)", R"(/foo/../bar)"},
159       {R"(/foo/bar)", R"(/foo/./bar)"},
160       {R"(/foo/bar)", R"(/foo/bar/.)"},
161   };
162 
163   for (const auto &test : tests) {
164     FileSpec one(test.first, false, FileSpec::Style::posix);
165     FileSpec two(test.second, false, FileSpec::Style::posix);
166     EXPECT_EQ(one, two);
167   }
168 }
169 
170 TEST(FileSpecTest, EqualDotsPosixRoot) {
171   std::pair<const char *, const char *> tests[] = {
172       {R"(/)", R"(/..)"},
173       {R"(/)", R"(/.)"},
174       {R"(/)", R"(/foo/..)"},
175   };
176 
177   for (const auto &test : tests) {
178     FileSpec one(test.first, false, FileSpec::Style::posix);
179     FileSpec two(test.second, false, FileSpec::Style::posix);
180     EXPECT_EQ(one, two);
181   }
182 }
183 
184 TEST(FileSpecTest, GetNormalizedPath) {
185   std::pair<const char *, const char *> posix_tests[] = {
186       {"/foo/.././bar", "/bar"},
187       {"/foo/./../bar", "/bar"},
188       {"/foo/../bar", "/bar"},
189       {"/foo/./bar", "/foo/bar"},
190       {"/foo/..", "/"},
191       {"/foo/.", "/foo"},
192       {"/foo//bar", "/foo/bar"},
193       {"/foo//bar/baz", "/foo/bar/baz"},
194       {"/foo//bar/./baz", "/foo/bar/baz"},
195       {"/./foo", "/foo"},
196       {"/", "/"},
197       {"//", "/"},
198       {"//net", "//net"},
199       {"/..", "/"},
200       {"/.", "/"},
201       {"..", ".."},
202       {".", ""},
203       {"../..", "../.."},
204       {"foo/..", ""},
205       {"foo/../bar", "bar"},
206       {"../foo/..", ".."},
207       {"./foo", "foo"},
208       {"././foo", "foo"},
209       {"../foo", "../foo"},
210       {"../../foo", "../../foo"},
211   };
212   for (auto test : posix_tests) {
213     SCOPED_TRACE(llvm::Twine("test.first = ") + test.first);
214     EXPECT_EQ(test.second,
215               FileSpec(test.first, false, FileSpec::Style::posix).GetPath());
216   }
217 
218   std::pair<const char *, const char *> windows_tests[] = {
219       {R"(c:\bar\..\bar)", R"(c:\bar)"},
220       {R"(c:\bar\.\bar)", R"(c:\bar\bar)"},
221       {R"(c:\bar\..)", R"(c:\)"},
222       {R"(c:\bar\.)", R"(c:\bar)"},
223       {R"(c:\.\bar)", R"(c:\bar)"},
224       {R"(\)", R"(\)"},
225       {R"(\\)", R"(\)"},
226       {R"(\\net)", R"(\\net)"},
227       {R"(c:\..)", R"(c:\)"},
228       {R"(c:\.)", R"(c:\)"},
229       // TODO: fix llvm::sys::path::remove_dots() to return "\" below.
230       {R"(\..)", R"(\..)"},
231       //      {R"(c:..)", R"(c:..)"},
232       {R"(..)", R"(..)"},
233       {R"(.)", R"()"},
234       // TODO: fix llvm::sys::path::remove_dots() to return "c:\" below.
235       {R"(c:..\..)", R"(c:\..\..)"},
236       {R"(..\..)", R"(..\..)"},
237       {R"(foo\..)", R"()"},
238       {R"(foo\..\bar)", R"(bar)"},
239       {R"(..\foo\..)", R"(..)"},
240       {R"(.\foo)", R"(foo)"},
241       {R"(.\.\foo)", R"(foo)"},
242       {R"(..\foo)", R"(..\foo)"},
243       {R"(..\..\foo)", R"(..\..\foo)"},
244   };
245   for (auto test : windows_tests) {
246     EXPECT_EQ(test.second,
247               FileSpec(test.first, false, FileSpec::Style::windows).GetPath())
248         << "Original path: " << test.first;
249   }
250 }
251 
252 TEST(FileSpecTest, FormatFileSpec) {
253   auto win = FileSpec::Style::windows;
254 
255   FileSpec F;
256   EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str());
257   EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
258   EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str());
259 
260   F = FileSpec("C:\\foo\\bar.txt", false, win);
261   EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str());
262   EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str());
263   EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
264 
265   F = FileSpec("foo\\bar.txt", false, win);
266   EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str());
267   EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str());
268   EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
269 
270   F = FileSpec("foo", false, win);
271   EXPECT_EQ("foo", llvm::formatv("{0}", F).str());
272   EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str());
273   EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
274 }
275 
276