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", 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", 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("/", 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_net_drive("//net", FileSpec::Style::posix); 34 EXPECT_STREQ("//net", fs_net_drive.GetCString()); 35 EXPECT_EQ(nullptr, fs_net_drive.GetDirectory().GetCString()); 36 EXPECT_STREQ("//net", fs_net_drive.GetFilename().GetCString()); 37 38 FileSpec fs_net_root("//net/", FileSpec::Style::posix); 39 EXPECT_STREQ("//net/", fs_net_root.GetCString()); 40 EXPECT_STREQ("//net", fs_net_root.GetDirectory().GetCString()); 41 EXPECT_STREQ("/", fs_net_root.GetFilename().GetCString()); 42 43 FileSpec fs_windows_drive("F:", FileSpec::Style::windows); 44 EXPECT_STREQ("F:", fs_windows_drive.GetCString()); 45 EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString()); 46 EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString()); 47 48 FileSpec fs_windows_root("F:\\", FileSpec::Style::windows); 49 EXPECT_STREQ("F:\\", fs_windows_root.GetCString()); 50 EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString()); 51 // EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString()); // It 52 // returns "/" 53 54 FileSpec fs_posix_long("/foo/bar/baz", FileSpec::Style::posix); 55 EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString()); 56 EXPECT_STREQ("/foo/bar", fs_posix_long.GetDirectory().GetCString()); 57 EXPECT_STREQ("baz", fs_posix_long.GetFilename().GetCString()); 58 59 FileSpec fs_windows_long("F:\\bar\\baz", FileSpec::Style::windows); 60 EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString()); 61 // EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString()); // It 62 // returns "F:/bar" 63 EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString()); 64 65 FileSpec fs_posix_trailing_slash("/foo/bar/", FileSpec::Style::posix); 66 EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetCString()); 67 EXPECT_STREQ("/foo", fs_posix_trailing_slash.GetDirectory().GetCString()); 68 EXPECT_STREQ("bar", fs_posix_trailing_slash.GetFilename().GetCString()); 69 70 FileSpec fs_windows_trailing_slash("F:\\bar\\", FileSpec::Style::windows); 71 EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetCString()); 72 EXPECT_STREQ("bar", fs_windows_trailing_slash.GetFilename().GetCString()); 73 } 74 75 TEST(FileSpecTest, AppendPathComponent) { 76 FileSpec fs_posix("/foo", FileSpec::Style::posix); 77 fs_posix.AppendPathComponent("bar"); 78 EXPECT_STREQ("/foo/bar", fs_posix.GetCString()); 79 EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString()); 80 EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString()); 81 82 FileSpec fs_posix_2("/foo", FileSpec::Style::posix); 83 fs_posix_2.AppendPathComponent("//bar/baz"); 84 EXPECT_STREQ("/foo/bar/baz", fs_posix_2.GetCString()); 85 EXPECT_STREQ("/foo/bar", fs_posix_2.GetDirectory().GetCString()); 86 EXPECT_STREQ("baz", fs_posix_2.GetFilename().GetCString()); 87 88 FileSpec fs_windows("F:\\bar", FileSpec::Style::windows); 89 fs_windows.AppendPathComponent("baz"); 90 EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString()); 91 // EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It 92 // returns "F:/bar" 93 EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString()); 94 95 FileSpec fs_posix_root("/", FileSpec::Style::posix); 96 fs_posix_root.AppendPathComponent("bar"); 97 EXPECT_STREQ("/bar", fs_posix_root.GetCString()); 98 EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString()); 99 EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString()); 100 101 FileSpec fs_windows_root("F:\\", FileSpec::Style::windows); 102 fs_windows_root.AppendPathComponent("bar"); 103 EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString()); 104 // EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It 105 // returns "F:/" 106 EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString()); 107 } 108 109 TEST(FileSpecTest, CopyByAppendingPathComponent) { 110 FileSpec fs = FileSpec("/foo", FileSpec::Style::posix) 111 .CopyByAppendingPathComponent("bar"); 112 EXPECT_STREQ("/foo/bar", fs.GetCString()); 113 EXPECT_STREQ("/foo", fs.GetDirectory().GetCString()); 114 EXPECT_STREQ("bar", fs.GetFilename().GetCString()); 115 } 116 117 TEST(FileSpecTest, PrependPathComponent) { 118 FileSpec fs_posix("foo", FileSpec::Style::posix); 119 fs_posix.PrependPathComponent("/bar"); 120 EXPECT_STREQ("/bar/foo", fs_posix.GetCString()); 121 122 FileSpec fs_posix_2("foo/bar", FileSpec::Style::posix); 123 fs_posix_2.PrependPathComponent("/baz"); 124 EXPECT_STREQ("/baz/foo/bar", fs_posix_2.GetCString()); 125 126 FileSpec fs_windows("baz", FileSpec::Style::windows); 127 fs_windows.PrependPathComponent("F:\\bar"); 128 EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString()); 129 130 FileSpec fs_posix_root("bar", FileSpec::Style::posix); 131 fs_posix_root.PrependPathComponent("/"); 132 EXPECT_STREQ("/bar", fs_posix_root.GetCString()); 133 134 FileSpec fs_windows_root("bar", FileSpec::Style::windows); 135 fs_windows_root.PrependPathComponent("F:\\"); 136 EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString()); 137 } 138 139 TEST(FileSpecTest, EqualSeparator) { 140 FileSpec backward("C:\\foo\\bar", FileSpec::Style::windows); 141 FileSpec forward("C:/foo/bar", FileSpec::Style::windows); 142 EXPECT_EQ(forward, backward); 143 } 144 145 TEST(FileSpecTest, EqualDotsWindows) { 146 std::pair<const char *, const char *> tests[] = { 147 {R"(C:\foo\bar\baz)", R"(C:\foo\foo\..\bar\baz)"}, 148 {R"(C:\bar\baz)", R"(C:\foo\..\bar\baz)"}, 149 {R"(C:\bar\baz)", R"(C:/foo/../bar/baz)"}, 150 {R"(C:/bar/baz)", R"(C:\foo\..\bar\baz)"}, 151 {R"(C:\bar)", R"(C:\foo\..\bar)"}, 152 {R"(C:\foo\bar)", R"(C:\foo\.\bar)"}, 153 {R"(C:\foo\bar)", R"(C:\foo\bar\.)"}, 154 }; 155 156 for (const auto &test : tests) { 157 FileSpec one(test.first, FileSpec::Style::windows); 158 FileSpec two(test.second, FileSpec::Style::windows); 159 EXPECT_EQ(one, two); 160 } 161 } 162 163 TEST(FileSpecTest, EqualDotsPosix) { 164 std::pair<const char *, const char *> tests[] = { 165 {R"(/foo/bar/baz)", R"(/foo/foo/../bar/baz)"}, 166 {R"(/bar/baz)", R"(/foo/../bar/baz)"}, 167 {R"(/bar)", R"(/foo/../bar)"}, 168 {R"(/foo/bar)", R"(/foo/./bar)"}, 169 {R"(/foo/bar)", R"(/foo/bar/.)"}, 170 }; 171 172 for (const auto &test : tests) { 173 FileSpec one(test.first, FileSpec::Style::posix); 174 FileSpec two(test.second, FileSpec::Style::posix); 175 EXPECT_EQ(one, two); 176 } 177 } 178 179 TEST(FileSpecTest, EqualDotsPosixRoot) { 180 std::pair<const char *, const char *> tests[] = { 181 {R"(/)", R"(/..)"}, 182 {R"(/)", R"(/.)"}, 183 {R"(/)", R"(/foo/..)"}, 184 }; 185 186 for (const auto &test : tests) { 187 FileSpec one(test.first, FileSpec::Style::posix); 188 FileSpec two(test.second, FileSpec::Style::posix); 189 EXPECT_EQ(one, two); 190 } 191 } 192 193 TEST(FileSpecTest, GetNormalizedPath) { 194 std::pair<const char *, const char *> posix_tests[] = { 195 {"/foo/.././bar", "/bar"}, 196 {"/foo/./../bar", "/bar"}, 197 {"/foo/../bar", "/bar"}, 198 {"/foo/./bar", "/foo/bar"}, 199 {"/foo/..", "/"}, 200 {"/foo/.", "/foo"}, 201 {"/foo//bar", "/foo/bar"}, 202 {"/foo//bar/baz", "/foo/bar/baz"}, 203 {"/foo//bar/./baz", "/foo/bar/baz"}, 204 {"/./foo", "/foo"}, 205 {"/", "/"}, 206 {"//", "/"}, 207 {"//net", "//net"}, 208 {"/..", "/"}, 209 {"/.", "/"}, 210 {"..", ".."}, 211 {".", "."}, 212 {"../..", "../.."}, 213 {"foo/..", "."}, 214 {"foo/../bar", "bar"}, 215 {"../foo/..", ".."}, 216 {"./foo", "foo"}, 217 {"././foo", "foo"}, 218 {"../foo", "../foo"}, 219 {"../../foo", "../../foo"}, 220 }; 221 for (auto test : posix_tests) { 222 SCOPED_TRACE(llvm::Twine("test.first = ") + test.first); 223 EXPECT_EQ(test.second, 224 FileSpec(test.first, FileSpec::Style::posix).GetPath()); 225 } 226 227 std::pair<const char *, const char *> windows_tests[] = { 228 {R"(c:\bar\..\bar)", R"(c:\bar)"}, 229 {R"(c:\bar\.\bar)", R"(c:\bar\bar)"}, 230 {R"(c:\bar\..)", R"(c:\)"}, 231 {R"(c:\bar\.)", R"(c:\bar)"}, 232 {R"(c:\.\bar)", R"(c:\bar)"}, 233 {R"(\)", R"(\)"}, 234 {R"(\\)", R"(\)"}, 235 {R"(\\net)", R"(\\net)"}, 236 {R"(c:\..)", R"(c:\)"}, 237 {R"(c:\.)", R"(c:\)"}, 238 // TODO: fix llvm::sys::path::remove_dots() to return "\" below. 239 {R"(\..)", R"(\..)"}, 240 // {R"(c:..)", R"(c:..)"}, 241 {R"(..)", R"(..)"}, 242 {R"(.)", R"(.)"}, 243 // TODO: fix llvm::sys::path::remove_dots() to return "c:\" below. 244 {R"(c:..\..)", R"(c:\..\..)"}, 245 {R"(..\..)", R"(..\..)"}, 246 {R"(foo\..)", R"(.)"}, 247 {R"(foo\..\bar)", R"(bar)"}, 248 {R"(..\foo\..)", R"(..)"}, 249 {R"(.\foo)", R"(foo)"}, 250 {R"(.\.\foo)", R"(foo)"}, 251 {R"(..\foo)", R"(..\foo)"}, 252 {R"(..\..\foo)", R"(..\..\foo)"}, 253 }; 254 for (auto test : windows_tests) { 255 EXPECT_EQ(test.second, 256 FileSpec(test.first, FileSpec::Style::windows).GetPath()) 257 << "Original path: " << test.first; 258 } 259 } 260 261 TEST(FileSpecTest, FormatFileSpec) { 262 auto win = FileSpec::Style::windows; 263 264 FileSpec F; 265 EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str()); 266 EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str()); 267 EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str()); 268 269 F = FileSpec("C:\\foo\\bar.txt", win); 270 EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str()); 271 EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str()); 272 EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str()); 273 274 F = FileSpec("foo\\bar.txt", win); 275 EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str()); 276 EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str()); 277 EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str()); 278 279 F = FileSpec("foo", win); 280 EXPECT_EQ("foo", llvm::formatv("{0}", F).str()); 281 EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str()); 282 EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str()); 283 } 284 285 TEST(FileSpecTest, IsRelative) { 286 llvm::StringRef not_relative[] = { 287 "/", 288 "/a", 289 "/a/", 290 "/a/b", 291 "/a/b/", 292 "//", 293 "//a/", 294 "//a/b", 295 "//a/b/", 296 "~", 297 "~/", 298 "~/a", 299 "~/a/", 300 "~/a/b" 301 "~/a/b/", 302 "/foo/.", 303 "/foo/..", 304 "/foo/../", 305 "/foo/../.", 306 }; 307 for (const auto &path: not_relative) { 308 FileSpec spec(path, FileSpec::Style::posix); 309 EXPECT_FALSE(spec.IsRelative()); 310 } 311 llvm::StringRef is_relative[] = { 312 ".", 313 "./", 314 ".///", 315 "a", 316 "./a", 317 "./a/", 318 "./a/", 319 "./a/b", 320 "./a/b/", 321 "../foo", 322 "foo/bar.c", 323 "./foo/bar.c" 324 }; 325 for (const auto &path: is_relative) { 326 FileSpec spec(path, FileSpec::Style::posix); 327 EXPECT_TRUE(spec.IsRelative()); 328 } 329 } 330 331 TEST(FileSpecTest, RemoveLastPathComponent) { 332 FileSpec fs_posix("/foo/bar/baz", FileSpec::Style::posix); 333 EXPECT_STREQ("/foo/bar/baz", fs_posix.GetCString()); 334 EXPECT_TRUE(fs_posix.RemoveLastPathComponent()); 335 EXPECT_STREQ("/foo/bar", fs_posix.GetCString()); 336 EXPECT_TRUE(fs_posix.RemoveLastPathComponent()); 337 EXPECT_STREQ("/foo", fs_posix.GetCString()); 338 EXPECT_TRUE(fs_posix.RemoveLastPathComponent()); 339 EXPECT_STREQ("/", fs_posix.GetCString()); 340 EXPECT_FALSE(fs_posix.RemoveLastPathComponent()); 341 EXPECT_STREQ("/", fs_posix.GetCString()); 342 343 FileSpec fs_posix_relative("./foo/bar/baz", FileSpec::Style::posix); 344 EXPECT_STREQ("foo/bar/baz", fs_posix_relative.GetCString()); 345 EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent()); 346 EXPECT_STREQ("foo/bar", fs_posix_relative.GetCString()); 347 EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent()); 348 EXPECT_STREQ("foo", fs_posix_relative.GetCString()); 349 EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent()); 350 EXPECT_STREQ("foo", fs_posix_relative.GetCString()); 351 352 FileSpec fs_posix_relative2("./", FileSpec::Style::posix); 353 EXPECT_STREQ(".", fs_posix_relative2.GetCString()); 354 EXPECT_FALSE(fs_posix_relative2.RemoveLastPathComponent()); 355 EXPECT_STREQ(".", fs_posix_relative2.GetCString()); 356 EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent()); 357 EXPECT_STREQ(".", fs_posix_relative2.GetCString()); 358 359 FileSpec fs_windows("C:\\foo\\bar\\baz", FileSpec::Style::windows); 360 EXPECT_STREQ("C:\\foo\\bar\\baz", fs_windows.GetCString()); 361 EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); 362 EXPECT_STREQ("C:\\foo\\bar", fs_windows.GetCString()); 363 EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); 364 EXPECT_STREQ("C:\\foo", fs_windows.GetCString()); 365 EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); 366 EXPECT_STREQ("C:\\", fs_windows.GetCString()); 367 EXPECT_TRUE(fs_windows.RemoveLastPathComponent()); 368 EXPECT_STREQ("C:", fs_windows.GetCString()); 369 EXPECT_FALSE(fs_windows.RemoveLastPathComponent()); 370 EXPECT_STREQ("C:", fs_windows.GetCString()); 371 } 372