// Copyright 2020-2022 David Robillard // SPDX-License-Identifier: ISC /* Tests that compare results with std::filesystem::path. Also serves as a handy record of divergence between zix, the C++ standard library, and different implementations of it. The inconsistencies are confined to Windows. */ #undef NDEBUG #include "zix/path.h" #include "zix/string_view.h" #include #include #include #include #include struct BinaryCase { const char* lhs; const char* rhs; }; static const BinaryCase joins[] = { {"", ""}, {"", "/b/"}, {"", "b"}, {"/", ""}, {"..", ".."}, {"..", "name"}, {"..", "/"}, {"/", ".."}, {"/", nullptr}, {"//host", ""}, {"//host", "a"}, {"//host/", "a"}, {"/a", ""}, {"/a", "/b"}, {"/a", "/b/"}, {"/a", "b"}, {"/a", "b/"}, {"/a", nullptr}, {"/a/", ""}, {"/a/", "b"}, {"/a/", "b/"}, {"/a/", nullptr}, {"/a/b", nullptr}, {"/a/b/", ""}, {"/a/b/", nullptr}, {"/a/c", "b"}, {"/a/c/", "/b/d"}, {"/a/c/", "b"}, {"C:", ""}, {"C:/a", "/b"}, {"C:/a", "C:/b"}, {"C:/a", "C:b"}, {"C:/a", "D:b"}, {"C:/a", "b"}, {"C:/a", "b/"}, {"C:/a", "c:/b"}, {"C:/a", "c:b"}, {"C:\\a", "b"}, {"C:\\a", "b\\"}, {"C:a", "/b"}, {"C:a", "C:/b"}, {"C:a", "C:\\b"}, {"C:a", "C:b"}, {"C:a", "b"}, {"C:a", "c:/b"}, {"C:a", "c:\\b"}, {"C:a", "c:b"}, {"a", ""}, {"a", "/b"}, {"a", "C:"}, {"a", "C:/b"}, {"a", "C:\\b"}, {"a", "\\b"}, {"a", "b"}, {"a", "b/"}, {"a", nullptr}, {"a/", ""}, {"a/", "/b"}, {"a/", "b"}, {"a/", "b/"}, {"a/", nullptr}, {"a/b", ""}, {"a/b", nullptr}, {"a/b/", ""}, {"a/b/", nullptr}, {"a\\", "\\b"}, {"a\\", "b"}, {nullptr, "/b"}, {nullptr, "/b/c"}, {nullptr, "b"}, {nullptr, "b/c"}, {nullptr, nullptr}, }; static const BinaryCase lexical_relatives[] = { {"", ""}, {"", "."}, {".", "."}, {"../", "../"}, {"../", "./"}, {"../", "a"}, {"../../a", "../b"}, {"../a", "../b"}, {"/", "/a/b"}, {"/", "/a/b/c"}, {"/", "a"}, {"/", "a/b"}, {"/", "a/b/c"}, {"//host", "//host"}, {"//host/", "//host/"}, {"//host/a/b", "//host/a/b"}, {"/a", "/b/c/"}, {"/a/", "/a/b"}, {"/a/", "/b/c"}, {"/a/", "/b/c/"}, {"/a/", "b"}, {"/a/", "b/c/"}, {"/a/b", "a/b"}, {"/a/b/c", "/a/b/d/"}, {"/a/b/c", "/a/b/d/e/"}, {"/a/b/c", "/a/d"}, {"C:", "C:a.txt"}, {"C:", "D:a.txt"}, {"C:../", "C:../"}, {"C:../", "C:./"}, {"C:../", "C:a"}, {"C:../../a", "C:../b"}, {"C:../a", "C:../b"}, {"C:/", "C:a.txt"}, {"C:/", "D:a.txt"}, {"C:/D/", "C:F"}, {"C:/D/", "C:F.txt"}, {"C:/D/S/", "F"}, {"C:/D/S/", "F.txt"}, {"C:/Dir/", "C:/Dir/File.txt"}, {"C:/Dir/", "C:File.txt"}, {"C:/Dir/File.txt", "C:/Dir/Sub/"}, {"C:/Dir/File.txt", "C:/Other.txt"}, {"C:/Dir/Sub/", "File.txt"}, {"C:/a.txt", "C:/b/c.txt"}, {"C:/a/", "C:/a/b.txt"}, {"C:/a/", "C:b.txt"}, {"C:/a/b.txt", "C:/a/b/"}, {"C:/a/b.txt", "C:/d.txt"}, {"C:/a/b/", "d.txt"}, {"C:/b/", "C:a.txt"}, {"C:/b/c/", "a.txt"}, {"C:F", "D:G"}, {"C:File.txt", "D:Other.txt"}, {"C:a.txt", "C:b.txt"}, {"C:a.txt", "D:"}, {"C:a.txt", "D:/"}, {"C:a.txt", "D:e.txt"}, {"C:a/b/c", "C:../"}, {"C:a/b/c", "C:../../"}, {"a", "a"}, {"a", "a/b/c"}, {"a", "b/c"}, {"a/b", "a/b"}, {"a/b", "c/d"}, {"a/b/c", "../"}, {"a/b/c", "../../"}, {"a/b/c", "a/b/c"}, {"a/b/c", "a/b/c/x/y"}, {"a/b/c/", "a/b/c/"}, // Network paths that aren't supported by MinGW #if !(defined(_WIN32) && defined(__GLIBCXX__)) {"//host", "//host/"}, {"//host", "a"}, {"//host", "a"}, {"//host/", "a"}, {"//host/", "a"}, #endif }; static const char* const paths[] = { // Valid paths handled consistently on all platforms "", ".", "..", "../", "../..", "../../", "../../a", "../a", "../name", "..\\..\\a", "..\\a", "..name", "./", "./.", "./..", ".//a//.//./b/.//", "./a/././b/./", "./name", ".hidden", ".hidden.txt", "/", "/.", "/..", "/../", "/../..", "/../../", "/../a", "/../a/../..", "//", "///", "///dir/", "///dir///", "///dir///name", "///dir///sub/////", "///name", "/a", "/a/", "/a/b", "/a/b/", "/a\\", "/a\\b", "/a\\b/", "/dir/", "/dir/.", "/dir/..", "/dir/../..", "/dir/.hidden", "/dir//name", "/dir//sub/suub/", "/dir/name", "/dir/name.tar.gz", "/dir/name.txt", "/dir/name\\", "/dir/sub/", "/dir/sub/./", "/dir/sub//", "/dir/sub///", "/dir/sub//name", "/dir/sub/name", "/dir/sub/suub/", "/dir/sub/suub/../", "/dir/sub/suub/../d", "/dir/sub/suub/../d/", "/dir/sub/suub/suuub/", "/dir/sub\\name", "/name", "/name.", "/name.txt", "/name.txt.", "C:", "C:.", "C:..", "C:/", "C:/.", "C:/..", "C:/../../name", "C:/../name", "C:/..dir/..name", "C:/..name", "C:/./name", "C:/.dir/../name", "C:/.dir/.hidden", "C:/.hidden", "C:/dir/", "C:/dir/.", "C:/dir/..", "C:/dir/name", "C:/dir/sub/", "C:/dir/sub/name", "C:/dir/sub/suub/", "C:/dir/sub/suub/suuub/", "C:/name", "C:/name.", "C:/name.txt", "C:/name\\horror", "C:/name\\horror/", "C:\\", "C:\\a", "C:\\a/", "C:\\a/b", "C:\\a/b\\", "C:\\a\\", "C:\\a\\b", "C:\\a\\b\\", "C:\\a\\b\\c", "C:\\a\\b\\d\\", "C:\\a\\b\\d\\e\\", "C:\\b", "C:\\b\\c\\", "C:a", "C:dir/", "C:dir/name", "C:dir\\", "C:name", "C:name/", "C:name\\horror", "D|\\dir\\name", "D|\\name", "D|name", "Z:/a/b", "Z:\\a\\b", "Z:b", "\\", "\\a\\/b\\/c\\", "\\a\\b\\c\\", "\\b", "a", "a.", "a..txt", "a.txt", "a/b", "a/b\\", "c:/name", "c:\\name", "c:name", "dir/", "dir/.", "dir/..", "dir/../", "dir/../b", "dir/../b/../..///", "dir/../b/..//..///../", "dir/../sub/../name", "dir/./", "dir/.///b/../", "dir/./b", "dir/./b/.", "dir/./b/..", "dir/./sub/./name", "dir///b", "dir//b", "dir/\\b", "dir/b", "dir/b.", "dir/name", "dir/name.", "dir/name.tar.gz", "dir/name.txt", "dir/name.txt.", "dir/name\\with\\backslashes", "dir/sub/", "dir/sub/.", "dir/sub/..", "dir/sub/../", "dir/sub/../..", "dir/sub/../../", "dir/sub/../name", "dir/sub/./", "dir/sub/./..", "dir/sub/./../", "dir/sub/./name", "dir/sub//", "dir/sub///", "dir/sub/name", "dir/sub/suub/../..", "dir/sub/suub/../../", "dir/weird