path.cpp (7642B)
1 #include "helper.hpp" 2 3 #include <path.hpp> 4 5 using Catch::Matchers::StartsWith; 6 7 static const char *M = "[path]"; 8 9 TEST_CASE("compare paths", M) { 10 const Path a = Path("hello"); 11 const Path b = Path("world"); 12 13 REQUIRE_FALSE(a == b); 14 REQUIRE(a != b); 15 16 REQUIRE(a == a); 17 REQUIRE_FALSE(a != a); 18 } 19 20 TEST_CASE("append path segments", M) { 21 Path path; 22 REQUIRE(path.empty()); 23 REQUIRE(path.size() == 0); 24 25 path.append(std::string{}); 26 REQUIRE(path.empty()); 27 REQUIRE(path.size() == 0); 28 29 path.append("foo"); 30 REQUIRE_FALSE(path.empty()); 31 REQUIRE(path.size() == 1); 32 33 path.append("bar"); 34 REQUIRE(path.size() == 2); 35 36 path.append("baz"); 37 REQUIRE(path.size() == 3); 38 } 39 40 TEST_CASE("path dirname", M) { 41 Path path; 42 REQUIRE(path.dirname().empty()); 43 44 path.append("foo"); 45 REQUIRE(path.dirname().empty()); 46 47 path.append("bar"); 48 REQUIRE(path.dirname() == Path("foo")); 49 50 path.append("baz"); 51 REQUIRE(path.dirname() == Path("foo/bar")); 52 } 53 54 TEST_CASE("path basename", M) { 55 Path path; 56 REQUIRE(path.basename().empty()); 57 58 path.append("foo"); 59 REQUIRE(path.basename() == "foo"); 60 61 path.append("bar"); 62 REQUIRE(path.basename() == "bar"); 63 } 64 65 TEST_CASE("path first segment", M) { 66 Path path; 67 REQUIRE(path.front().empty()); 68 69 path.append("foo"); 70 REQUIRE(path.front() == "foo"); 71 } 72 73 TEST_CASE("concatenate paths", M) { 74 const Path a("hello"); 75 const Path b("world"); 76 77 Path c; 78 c.append("hello"); 79 c += "world"; 80 81 REQUIRE(a + b == c); 82 REQUIRE(a + "world" == c); 83 } 84 85 TEST_CASE("strip trailing/leading slashes", M) { 86 Path a; 87 a.append("a/b/"); 88 a.append("/c/d/"); 89 a.append(Path("/e/f/")); 90 91 REQUIRE(a.size() == 6); 92 #ifndef _WIN32 93 REQUIRE(a.join() == "a/b/c/d/e/f"); 94 #else 95 REQUIRE(a.join() == "a\\b\\c\\d\\e\\f"); 96 #endif 97 } 98 99 TEST_CASE("clear path", M) { 100 Path a; 101 a.append("test"); 102 CHECK(a.size() == 1); 103 104 a.clear(); 105 REQUIRE(a.size() == 0); 106 } 107 108 TEST_CASE("modify path", M) { 109 Path a; 110 a.append("hello"); 111 112 a[0] = "world"; 113 REQUIRE(a.join() == "world"); 114 } 115 116 TEST_CASE("force unix separator", M) { 117 Path a; 118 a.append("hello"); 119 a.append("world"); 120 121 REQUIRE(a.join(false) == "hello/world"); 122 } 123 124 TEST_CASE("split input", M) { 125 SECTION("slash") { 126 const Path a("hello/world"); 127 128 REQUIRE(a.size() == 2); 129 REQUIRE(a[0] == "hello"); 130 REQUIRE(a[1] == "world"); 131 } 132 133 SECTION("backslash") { 134 const Path a("hello\\world"); 135 136 REQUIRE(a.size() == 2); 137 REQUIRE(a[0] == "hello"); 138 REQUIRE(a[1] == "world"); 139 } 140 141 SECTION("append") { 142 Path a; 143 a.append("hello/world"); 144 REQUIRE(a.size() == 2); 145 146 a += "chunky/bacon"; 147 REQUIRE(a.size() == 4); 148 } 149 150 SECTION("skip empty parts") { 151 const Path a("hello//world/"); 152 153 REQUIRE(a.size() == 2); 154 REQUIRE(a[0] == "hello"); 155 REQUIRE(a[1] == "world"); 156 } 157 } 158 159 TEST_CASE("absolute path", M) { 160 CHECK_FALSE(Path("a/b").test(Path::Absolute)); 161 162 #ifdef _WIN32 163 const Path a("C:\\Windows\\System32"); 164 #else 165 const Path a("/usr/bin/zsh"); 166 #endif 167 168 REQUIRE(a.test(Path::Absolute)); 169 CHECK(a.size() == 3); 170 171 #ifdef _WIN32 172 CHECK(a[0] == "C:"); 173 CHECK(a.join() == "C:\\Windows\\System32"); 174 #else 175 CHECK(a[0] == "usr"); 176 CHECK(a.join() == "/usr/bin/zsh"); 177 #endif 178 } 179 180 TEST_CASE("absolute path (root only)", M) { 181 #ifdef _WIN32 182 const Path a("C:"); 183 #else 184 const Path a("/"); 185 #endif 186 187 REQUIRE(a.test(Path::Absolute)); 188 189 #ifdef _WIN32 190 CHECK(a.size() == 1); 191 CHECK(a[0] == "C:"); 192 CHECK(a.join() == "C:"); 193 #else 194 CHECK(a.size() == 0); 195 CHECK(a.join() == "/"); 196 #endif 197 } 198 199 TEST_CASE("append absolute path to empty path", M) { 200 #ifdef _WIN32 201 const Path abs("C:\\Windows\\"); 202 #else 203 const Path abs("/usr/bin"); 204 #endif 205 206 Path path; 207 path += abs; 208 209 CHECK(path == abs); 210 REQUIRE(path.test(Path::Absolute)); 211 } 212 213 TEST_CASE("extended absolute paths", M) { 214 #ifdef _WIN32 215 Path abs("C:\\"); 216 abs.append(std::string(245, 'a')); 217 218 CHECK(abs.test(Path::Absolute)); 219 REQUIRE_THAT(abs.join(), StartsWith("\\\\?\\")); 220 221 const Path path(std::string(500, 'a')); 222 CHECK_FALSE(path.test(Path::Absolute)); 223 #else 224 Path path("/hello"); 225 path.append(std::string(260, 'a')); 226 #endif 227 228 REQUIRE_THAT(path.join(), !StartsWith("\\\\?\\")); 229 } 230 231 #ifdef _WIN32 232 TEST_CASE("UNC path", M) { 233 const Path unc("\\\\FOO\\bar"); 234 REQUIRE(unc.test(Path::Absolute)); 235 REQUIRE(unc.test(Path::UNC)); 236 CHECK(unc.size() == 2); 237 238 CHECK(unc[0] == "FOO"); 239 CHECK(unc.join() == "\\\\FOO\\bar"); 240 } 241 242 TEST_CASE("UNC path extended", M) { 243 Path unc("\\\\FOO"); 244 unc.append(std::string(260, 'a')); 245 246 CHECK(unc.test(Path::Absolute)); 247 CHECK(unc.test(Path::UNC)); 248 REQUIRE_THAT(unc.join(), StartsWith("\\\\?\\UNC\\FOO")); 249 } 250 #else 251 TEST_CASE("compare absolute to relative path (unix)", M) { 252 REQUIRE(Path("/a/b") != Path("a/b")); 253 } 254 255 TEST_CASE("top-level unix absolute path (p=2359736)", M) { 256 Path p("/foo"); 257 REQUIRE(p[0] == "foo"); 258 } 259 #endif 260 261 TEST_CASE("remove last segment of path", M) { 262 Path a; 263 a.append("a"); 264 a.append("b"); 265 266 CHECK(a.size() == 2); 267 268 a.removeLast(); 269 270 REQUIRE(a.size() == 1); 271 REQUIRE(a[0] == "a"); 272 273 a.removeLast(); 274 REQUIRE(a.empty()); 275 276 a.removeLast(); // no crash 277 } 278 279 TEST_CASE("prepend root path", M) { 280 const Path path("world"); 281 282 REQUIRE(path.prependRoot() == Path("world")); 283 284 { 285 UseRootPath root(Path("hello")); 286 (void)root; 287 288 REQUIRE(path.prependRoot() == Path("hello/world")); 289 } 290 291 REQUIRE(path.prependRoot() == Path("world")); 292 } 293 294 TEST_CASE("remove root path", M) { 295 const Path path("hello/world"); 296 297 REQUIRE(path.removeRoot() == Path("hello/world")); 298 299 { 300 UseRootPath root(Path("hello")); 301 (void)root; 302 303 REQUIRE(path.removeRoot() == Path("world")); 304 } 305 306 REQUIRE(path.removeRoot() == Path("hello/world")); 307 } 308 309 TEST_CASE("append with directory traversal enabled", M) { 310 SECTION("dot") 311 REQUIRE(Path("a/./b/.") == Path("a/b")); 312 313 SECTION("dotdot") 314 REQUIRE(Path("a/../b") == Path("b")); 315 } 316 317 TEST_CASE("append with directory traversal disabled", M) { 318 Path a; 319 320 SECTION("dot") 321 a.append("a/./b/.", false); 322 323 SECTION("dotdot") 324 a.append("a/../b", false); 325 326 REQUIRE(a == Path("a/b")); 327 } 328 329 TEST_CASE("concatenate with directory traversal", M) { 330 SECTION("path + string") { 331 // concatenating a std::string to a path, directory traversal is applied 332 const Path a = Path("a/b/c") + "../../../d/e/f"; 333 REQUIRE(a == Path("d/e/f")); 334 } 335 336 SECTION("path + path") { 337 // here, the directory traversal segments are lost before concatenating 338 const Path b = Path("a/b/c") + Path("../../../d/e/f"); 339 REQUIRE(b == Path("a/b/c/d/e/f")); 340 } 341 } 342 343 TEST_CASE("append full paths", M) { 344 Path a; 345 a += Path("a/b"); 346 a.append(Path("c/d")); 347 a.append(Path("e/f")); 348 349 REQUIRE(a == Path("a/b/c/d/e/f")); 350 } 351 352 TEST_CASE("temporary path", M) { 353 TempPath a(Path("hello/world")); 354 355 REQUIRE(a.target() == Path("hello/world")); 356 REQUIRE(a.temp() == Path("hello/world.part")); 357 } 358 359 TEST_CASE("path starts with", M) { 360 const Path ref("a/b"); 361 362 REQUIRE(ref.startsWith(ref)); 363 REQUIRE(Path("a/b/c").startsWith(ref)); 364 #ifndef _WIN32 365 REQUIRE_FALSE(Path("/a/b/c").startsWith(ref)); 366 #endif 367 REQUIRE_FALSE(Path("0/a/b/c").startsWith(ref)); 368 REQUIRE_FALSE(Path("a").startsWith(ref)); 369 } 370 371 TEST_CASE("remove path segments", M) { 372 Path path("/a/b/c/d/e"); 373 374 SECTION("remove from start") { 375 path.remove(0, 1); 376 REQUIRE(path == Path("b/c/d/e")); 377 REQUIRE_FALSE(path.test(Path::Absolute)); 378 } 379 380 SECTION("remove from middle") { 381 path.remove(1, 2); 382 REQUIRE(path == Path("/a/d/e")); 383 #ifndef _WIN32 384 REQUIRE(path.test(Path::Absolute)); 385 #endif 386 } 387 388 SECTION("remove past the end") { 389 path.remove(4, 2); 390 path.remove(18, 1); 391 REQUIRE(path == Path("/a/b/c/d")); 392 } 393 }