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