diff options
author | Eric Fiselier <eric@efcs.ca> | 2018-04-02 23:03:41 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2018-04-02 23:03:41 +0000 |
commit | d7fae181c3954886257fb33d0a57b954b26da745 (patch) | |
tree | 841df55a810bc7446cf7afdd6811b3f1d79a3fc8 /libcxx/test/std/experimental/filesystem/class.path/path.member | |
parent | 298ffc609bf5c67079dbeb77e3f75e5bc18fde7a (diff) | |
download | bcm5719-llvm-d7fae181c3954886257fb33d0a57b954b26da745.tar.gz bcm5719-llvm-d7fae181c3954886257fb33d0a57b954b26da745.zip |
Implement filesystem NB comments, relative paths, and related issues.
This is a fairly large patch that implements all of the filesystem NB comments
and the relative paths changes (ex. adding weakly_canonical). These issues
and papers are all interrelated so their implementation couldn't be split up
nicely.
This patch upgrades <experimental/filesystem> to match the C++17 spec and not
the published experimental TS spec. Some of the changes in this patch are both
API and ABI breaking, however libc++ makes no guarantee about stability for
experimental implementations.
The major changes in this patch are:
* Implement NB comments for filesystem (P0492R2), including:
* Implement `perm_options` enum as part of NB comments, and update the
`permissions` function to match.
* Implement changes to `remove_filename` and `replace_filename`
* Implement changes to `path::stem()` and `path::extension()` which support
splitting examples like `.profile`.
* Change path iteration to return an empty path instead of '.' for trailing
separators.
* Change `operator/=` to handle absolute paths on the RHS.
* Change `absolute` to no longer accept a current path argument.
* Implement relative paths according to NB comments (P0219r1)
* Combine `path.cpp` and `operations.cpp` since some path functions require
access to the operations internals, and some fs operations require access
to the path parser.
llvm-svn: 329028
Diffstat (limited to 'libcxx/test/std/experimental/filesystem/class.path/path.member')
10 files changed, 381 insertions, 111 deletions
diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp index ca072d16114..11bc5dd9b86 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp @@ -31,6 +31,7 @@ #include "test_iterators.h" #include "count_new.hpp" #include "filesystem_test_helper.hpp" +#include "verbose_assert.h" struct AppendOperatorTestcase { @@ -45,13 +46,22 @@ const AppendOperatorTestcase Cases[] = {S(""), S(""), S("")} , {S("p1"), S("p2"), S("p1/p2")} , {S("p1/"), S("p2"), S("p1/p2")} - , {S("p1"), S("/p2"), S("p1/p2")} - , {S("p1/"), S("/p2"), S("p1//p2")} + , {S("p1"), S("/p2"), S("/p2")} + , {S("p1/"), S("/p2"), S("/p2")} , {S("p1"), S("\\p2"), S("p1/\\p2")} , {S("p1\\"), S("p2"), S("p1\\/p2")} , {S("p1\\"), S("\\p2"), S("p1\\/\\p2")} - , {S("p1"), S(""), S("p1")} , {S(""), S("p2"), S("p2")} + , {S("/p1"), S("p2"), S("/p1/p2")} + , {S("/p1"), S("/p2"), S("/p2")} + , {S("/p1/p3"), S("p2"), S("/p1/p3/p2")} + , {S("/p1/p3/"), S("p2"), S("/p1/p3/p2")} + , {S("/p1/"), S("p2"), S("/p1/p2")} + , {S("/p1/p3/"), S("/p2/p4"), S("/p2/p4")} + , {S("/"), S(""), S("/")} + , {S("/p1"), S("/p2/"), S("/p2/")} + , {S("p1"), S(""), S("p1/")} + , {S("p1/"), S(""), S("p1/")} }; @@ -59,7 +69,8 @@ const AppendOperatorTestcase LongLHSCases[] = { {S("p1"), S("p2"), S("p1/p2")} , {S("p1/"), S("p2"), S("p1/p2")} - , {S("p1"), S("/p2"), S("p1/p2")} + , {S("p1"), S("/p2"), S("/p2")} + , {S("/p1"), S("p2"), S("/p1/p2")} }; #undef S @@ -98,7 +109,7 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) DisableAllocationGuard g; LHS /= RHS; } - assert(LHS == E); + ASSERT_PRED(PathEq, LHS , E); } // basic_string_view { @@ -108,7 +119,7 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) DisableAllocationGuard g; LHS /= RHS; } - assert(LHS == E); + assert(PathEq(LHS, E)); } // CharT* { @@ -118,7 +129,7 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) DisableAllocationGuard g; LHS /= RHS; } - assert(LHS == E); + assert(PathEq(LHS, E)); } { path LHS(L); PathReserve(LHS, ReserveSize); @@ -127,7 +138,7 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) DisableAllocationGuard g; LHS.append(RHS, StrEnd(RHS)); } - assert(LHS == E); + assert(PathEq(LHS, E)); } // input iterator - For non-native char types, appends needs to copy the // iterator range into a contiguous block of memory before it can perform the @@ -143,7 +154,7 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) if (DisableAllocations) g.requireExactly(0); LHS /= RHS; } - assert(LHS == E); + assert(PathEq(LHS, E)); } { path LHS(L); PathReserve(LHS, ReserveSize); @@ -154,7 +165,7 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) if (DisableAllocations) g.requireExactly(0); LHS.append(RHS, REnd); } - assert(LHS == E); + assert(PathEq(LHS, E)); } } @@ -171,17 +182,18 @@ void doAppendSourceTest(AppendOperatorTestcase const& TC) const Ptr E = TC.expect; // basic_string { - path LHS(L); + path Result(L); Str RHS(R); - path& Ref = (LHS /= RHS); - assert(LHS == E); - assert(&Ref == &LHS); + path& Ref = (Result /= RHS); + ASSERT_EQ(Result, E) + << DISPLAY(L) << DISPLAY(R); + assert(&Ref == &Result); } { path LHS(L); Str RHS(R); path& Ref = LHS.append(RHS); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } // basic_string_view @@ -189,14 +201,14 @@ void doAppendSourceTest(AppendOperatorTestcase const& TC) path LHS(L); StrView RHS(R); path& Ref = (LHS /= RHS); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } { path LHS(L); StrView RHS(R); path& Ref = LHS.append(RHS); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } // Char* @@ -204,21 +216,22 @@ void doAppendSourceTest(AppendOperatorTestcase const& TC) path LHS(L); Str RHS(R); path& Ref = (LHS /= RHS); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } { path LHS(L); Ptr RHS(R); path& Ref = LHS.append(RHS); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } { path LHS(L); Ptr RHS(R); path& Ref = LHS.append(RHS, StrEnd(RHS)); - assert(LHS == E); + ASSERT_PRED(PathEq, LHS, E) + << DISPLAY(L) << DISPLAY(R); assert(&Ref == &LHS); } // iterators @@ -226,13 +239,13 @@ void doAppendSourceTest(AppendOperatorTestcase const& TC) path LHS(L); InputIter RHS(R); path& Ref = (LHS /= RHS); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } { path LHS(L); InputIter RHS(R); path& Ref = LHS.append(RHS); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } { @@ -240,7 +253,7 @@ void doAppendSourceTest(AppendOperatorTestcase const& TC) InputIter RHS(R); InputIter REnd(StrEnd(R)); path& Ref = LHS.append(RHS, REnd); - assert(LHS == E); + assert(PathEq(LHS, E)); assert(&Ref == &LHS); } } @@ -304,11 +317,14 @@ int main() using namespace fs; for (auto const & TC : Cases) { { - path LHS((const char*)TC.lhs); - path RHS((const char*)TC.rhs); - path& Ref = (LHS /= RHS); - assert(LHS == (const char*)TC.expect); - assert(&Ref == &LHS); + const char* LHS_In = TC.lhs; + const char* RHS_In = TC.rhs; + path LHS(LHS_In); + path RHS(RHS_In); + path& Res = (LHS /= RHS); + ASSERT_PRED(PathEq, Res, (const char*)TC.expect) + << DISPLAY(LHS_In) << DISPLAY(RHS_In); + assert(&Res == &LHS); } doAppendSourceTest<char> (TC); doAppendSourceTest<wchar_t> (TC); diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp index ea356782678..a2af094128d 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp @@ -26,6 +26,7 @@ // // size_t hash_value(path const&) noexcept; + #include "filesystem_include.hpp" #include <type_traits> #include <vector> @@ -35,7 +36,7 @@ #include "test_iterators.h" #include "count_new.hpp" #include "filesystem_test_helper.hpp" - +#include "verbose_assert.h" struct PathCompareTest { const char* LHS; @@ -57,8 +58,9 @@ const PathCompareTest CompareTestCases[] = {"a/b/c", "b/a/c", -1}, {"a/b", "a/b/c", -1}, {"a/b/c", "a/b", 1}, - {"a/b/", "a/b/.", 0}, - {"a/b//////", "a/b/////.", 0}, + {"a/b/", "a/b/.", -1}, + {"a/b/", "a/b", 1}, + {"a/b//////", "a/b/////.", -1}, {"a/.././b", "a///..//.////b", 0}, {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory @@ -94,8 +96,13 @@ int main() int ret2 = normalize_ret(p1.compare(R)); int ret3 = normalize_ret(p1.compare(TC.RHS)); int ret4 = normalize_ret(p1.compare(RV)); - assert(ret1 == ret2 && ret1 == ret3 && ret1 == ret4); - assert(ret1 == E); + + g.release(); + ASSERT_EQ(ret1, ret2); + ASSERT_EQ(ret1, ret3); + ASSERT_EQ(ret1, ret4); + ASSERT_EQ(ret1, E) + << DISPLAY(TC.LHS) << DISPLAY(TC.RHS); // check signatures ASSERT_NOEXCEPT(p1.compare(p2)); diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/empty.fail.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/empty.fail.cpp index 377b94e52c7..ecc4c0c30a0 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/empty.fail.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/empty.fail.cpp @@ -18,6 +18,7 @@ // UNSUPPORTED: clang-3.3, clang-3.4, clang-3.5, clang-3.6, clang-3.7, clang-3.8 #include "filesystem_include.hpp" + #include "test_macros.h" int main () diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp index 6dd24b51156..f959e43a304 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp @@ -53,6 +53,14 @@ #include "test_iterators.h" #include "count_new.hpp" #include "filesystem_test_helper.hpp" +#include "assert_checkpoint.h" +#include "verbose_assert.h" + +struct ComparePathExact { + bool operator()(std::string const& LHS, std::string const& RHS) const { + return LHS == RHS; + } +}; struct PathDecomposeTestcase { @@ -72,80 +80,89 @@ const PathDecomposeTestcase PathTestCases[] = , {".", {"."}, "", "", "", ".", "", "."} , {"..", {".."}, "", "", "", "..", "", ".."} , {"foo", {"foo"}, "", "", "", "foo", "", "foo"} - , {"/", {"/"}, "/", "", "/", "", "", "/"} + , {"/", {"/"}, "/", "", "/", "", "/", ""} , {"/foo", {"/", "foo"}, "/", "", "/", "foo", "/", "foo"} - , {"foo/", {"foo", "."}, "", "", "", "foo/", "foo", "."} - , {"/foo/", {"/", "foo", "."}, "/", "", "/", "foo/", "/foo", "."} + , {"foo/", {"foo", ""}, "", "", "", "foo/", "foo", ""} + , {"/foo/", {"/", "foo", ""}, "/", "", "/", "foo/", "/foo", ""} , {"foo/bar", {"foo","bar"}, "", "", "", "foo/bar", "foo", "bar"} , {"/foo//bar", {"/","foo","bar"}, "/", "", "/", "foo/bar", "/foo", "bar"} - , {"//net", {"//net"}, "//net", "//net", "", "", "", "//net"} - , {"//net/foo", {"//net", "/", "foo"}, "//net/", "//net", "/", "foo", "//net/", "foo"} - , {"///foo///", {"/", "foo", "."}, "/", "", "/", "foo///", "///foo", "."} + , {"//net", {"/", "net"}, "/", "", "/", "net", "/", "net"} + , {"//net/foo", {"/", "net", "foo"}, "/", "", "/", "net/foo", "/net", "foo"} + , {"///foo///", {"/", "foo", ""}, "/", "", "/", "foo///", "///foo", ""} , {"///foo///bar", {"/", "foo", "bar"}, "/", "", "/", "foo///bar", "///foo", "bar"} , {"/.", {"/", "."}, "/", "", "/", ".", "/", "."} - , {"./", {".", "."}, "", "", "", "./", ".", "."} + , {"./", {".", ""}, "", "", "", "./", ".", ""} , {"/..", {"/", ".."}, "/", "", "/", "..", "/", ".."} - , {"../", {"..", "."}, "", "", "", "../", "..", "."} + , {"../", {"..", ""}, "", "", "", "../", "..", ""} , {"foo/.", {"foo", "."}, "", "", "", "foo/.", "foo", "."} , {"foo/..", {"foo", ".."}, "", "", "", "foo/..", "foo", ".."} - , {"foo/./", {"foo", ".", "."}, "", "", "", "foo/./", "foo/.", "."} + , {"foo/./", {"foo", ".", ""}, "", "", "", "foo/./", "foo/.", ""} , {"foo/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar", "foo/.", "bar"} - , {"foo/../", {"foo", "..", "."}, "", "", "", "foo/../", "foo/..", "."} + , {"foo/../", {"foo", "..", ""}, "", "", "", "foo/../", "foo/..", ""} , {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar", "foo/..", "bar"} , {"c:", {"c:"}, "", "", "", "c:", "", "c:"} - , {"c:/", {"c:", "."}, "", "", "", "c:/", "c:", "."} + , {"c:/", {"c:", ""}, "", "", "", "c:/", "c:", ""} , {"c:foo", {"c:foo"}, "", "", "", "c:foo", "", "c:foo"} , {"c:/foo", {"c:", "foo"}, "", "", "", "c:/foo", "c:", "foo"} - , {"c:foo/", {"c:foo", "."}, "", "", "", "c:foo/", "c:foo", "."} - , {"c:/foo/", {"c:", "foo", "."}, "", "", "", "c:/foo/", "c:/foo", "."} + , {"c:foo/", {"c:foo", ""}, "", "", "", "c:foo/", "c:foo", ""} + , {"c:/foo/", {"c:", "foo", ""}, "", "", "", "c:/foo/", "c:/foo", ""} , {"c:/foo/bar", {"c:", "foo", "bar"}, "", "", "", "c:/foo/bar", "c:/foo", "bar"} , {"prn:", {"prn:"}, "", "", "", "prn:", "", "prn:"} , {"c:\\", {"c:\\"}, "", "", "", "c:\\", "", "c:\\"} , {"c:\\foo", {"c:\\foo"}, "", "", "", "c:\\foo", "", "c:\\foo"} , {"c:foo\\", {"c:foo\\"}, "", "", "", "c:foo\\", "", "c:foo\\"} , {"c:\\foo\\", {"c:\\foo\\"}, "", "", "", "c:\\foo\\", "", "c:\\foo\\"} - , {"c:\\foo/", {"c:\\foo", "."}, "", "", "", "c:\\foo/", "c:\\foo", "."} + , {"c:\\foo/", {"c:\\foo", ""}, "", "", "", "c:\\foo/", "c:\\foo", ""} , {"c:/foo\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar", "c:", "foo\\bar"} - , {"//", {"//"}, "//", "//", "", "", "", "//"} + , {"//", {"/"}, "/", "", "/", "", "/", ""} }; void decompPathTest() { using namespace fs; for (auto const & TC : PathTestCases) { - path p(TC.raw); - assert(p == TC.raw); + CHECKPOINT(TC.raw.c_str()); + fs::path p(TC.raw); + ASSERT(p == TC.raw); - assert(p.root_path() == TC.root_path); - assert(p.has_root_path() != TC.root_path.empty()); + ASSERT_EQ(p.root_path(), TC.root_path); + ASSERT_NEQ(p.has_root_path(), TC.root_path.empty()); - assert(p.root_name() == TC.root_name); - assert(p.has_root_name() != TC.root_name.empty()); + ASSERT(p.root_name().native().empty()) + << DISPLAY(p.root_name()); + ASSERT_EQ(p.root_name(),TC.root_name); + ASSERT_NEQ(p.has_root_name(), TC.root_name.empty()); - assert(p.root_directory() == TC.root_directory); - assert(p.has_root_directory() != TC.root_directory.empty()); + ASSERT_EQ(p.root_directory(), TC.root_directory); + ASSERT_NEQ(p.has_root_directory(), TC.root_directory.empty()); - assert(p.relative_path() == TC.relative_path); - assert(p.has_relative_path() != TC.relative_path.empty()); + ASSERT_EQ(p.relative_path(), TC.relative_path); + ASSERT_NEQ(p.has_relative_path(), TC.relative_path.empty()); - assert(p.parent_path() == TC.parent_path); - assert(p.has_parent_path() != TC.parent_path.empty()); + ASSERT_EQ(p.parent_path(), TC.parent_path); + ASSERT_NEQ(p.has_parent_path(), TC.parent_path.empty()); - assert(p.filename() == TC.filename); - assert(p.has_filename() != TC.filename.empty()); + ASSERT_EQ(p.filename(), TC.filename); + ASSERT_NEQ(p.has_filename(), TC.filename.empty()); - assert(p.is_absolute() == p.has_root_directory()); - assert(p.is_relative() != p.is_absolute()); + ASSERT_EQ(p.is_absolute(), p.has_root_directory()); + ASSERT_NEQ(p.is_relative(), p.is_absolute()); + if (p.empty()) + ASSERT(p.is_relative()); - assert(checkCollectionsEqual(p.begin(), p.end(), - TC.elements.begin(), TC.elements.end())); + ASSERT_COLLECTION_EQ_COMP( + p.begin(), p.end(), + TC.elements.begin(), TC.elements.end(), + ComparePathExact() + ); // check backwards std::vector<fs::path> Parts; for (auto it = p.end(); it != p.begin(); ) Parts.push_back(*--it); - assert(checkCollectionsEqual(Parts.begin(), Parts.end(), - TC.elements.rbegin(), TC.elements.rend())); + ASSERT_COLLECTION_EQ_COMP(Parts.begin(), Parts.end(), + TC.elements.rbegin(), TC.elements.rend(), + ComparePathExact()); } } @@ -163,10 +180,12 @@ const FilenameDecompTestcase FilenameTestCases[] = {"", "", "", ""} , {".", ".", ".", ""} , {"..", "..", "..", ""} - , {"/", "/", "/", ""} + , {"/", "", "", ""} , {"foo", "foo", "foo", ""} , {"/foo/bar.txt", "bar.txt", "bar", ".txt"} , {"foo..txt", "foo..txt", "foo.", ".txt"} + , {".profile", ".profile", ".profile", ""} + , {".profile.txt", ".profile.txt", ".profile", ".txt"} }; @@ -174,18 +193,19 @@ void decompFilenameTest() { using namespace fs; for (auto const & TC : FilenameTestCases) { - path p(TC.raw); - assert(p == TC.raw); + CHECKPOINT(TC.raw.c_str()); + fs::path p(TC.raw); + ASSERT_EQ(p, TC.raw); ASSERT_NOEXCEPT(p.empty()); - assert(p.filename() == TC.filename); - assert(p.has_filename() != TC.filename.empty()); + ASSERT_EQ(p.filename(), TC.filename); + ASSERT_NEQ(p.has_filename(), TC.filename.empty()); - assert(p.stem() == TC.stem); - assert(p.has_stem() != TC.stem.empty()); + ASSERT_EQ(p.stem(), TC.stem); + ASSERT_NEQ(p.has_stem(), TC.stem.empty()); - assert(p.extension() == TC.extension); - assert(p.has_extension() != TC.extension.empty()); + ASSERT_EQ(p.extension(), TC.extension); + ASSERT_NEQ(p.has_extension(), TC.extension.empty()); } } diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_normal.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_normal.pass.cpp new file mode 100644 index 00000000000..c897ab60f73 --- /dev/null +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_normal.pass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// <experimental/filesystem> + +// class path + +// path lexically_normal() const; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <vector> +#include <iostream> +#include <cassert> + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + + +int main() { + // clang-format off + struct { + std::string input; + std::string expect; + } TestCases[] = { + {"", ""}, + {"/a/b/c", "/a/b/c"}, + {"/a/b//c", "/a/b/c"}, + {"foo/./bar/..", "foo/"}, + {"foo/.///bar/../", "foo/"}, + {"/a/b/", "/a/b/"}, + {"a/b", "a/b"}, + {"a/b/.", "a/b/"}, + {"a/b/./", "a/b/"}, + {"a/..", "."}, + {".", "."}, + {"./", "."}, + {"./.", "."}, + {"./..", ".."}, + {"..", ".."}, + {"../..", "../.."}, + {"/../", "/"}, + {"/../..", "/"}, + {"/../../", "/"}, + {"..", ".."}, + {"../", ".."}, + {"/a/b/c/../", "/a/b/"}, + {"/a/b/./", "/a/b/"}, + {"/a/b/c/../d", "/a/b/d"}, + {"/a/b/c/../d/", "/a/b/d/"}, + {"//a/", "/a/"}, + {"//a/b/", "/a/b/"}, + {"//a/b/.", "/a/b/"}, + {"//a/..", "/"}, + ///===---------------------------------------------------------------===// + /// Tests specifically for the clauses under [fs.path.generic]p6 + ///===---------------------------------------------------------------===// + // p1: If the path is empty, stop. + {"", ""}, + // p2: Replace each slash character in the root-name with a preferred + // separator. + {"NO_ROOT_NAME_ON_LINUX", "NO_ROOT_NAME_ON_LINUX"}, + // p3: Replace each directory-separator with a preferred-separator. + // [ Note: The generic pathname grammar ([fs.path.generic]) defines + // directory-separator as one or more slashes and preferred-separators. + // — end note ] + {"/", "/"}, + {"//", "/"}, + {"///", "/"}, + {"a/b", "a/b"}, + {"a//b", "a/b"}, + {"a///b", "a/b"}, + {"a/b/", "a/b/"}, + {"a/b//", "a/b/"}, + {"a/b///", "a/b/"}, + {"///a////b//////", "/a/b/"}, + // p4: Remove each dot filename and any immediately following directory + // separators + {"foo/.", "foo/"}, + {"foo/./bar/.", "foo/bar/"}, + {"./foo/././bar/./", "foo/bar/"}, + {".///foo//.////./bar/.///", "foo/bar/"}, + // p5: As long as any appear, remove a non-dot-dot filename immediately + // followed by a directory-separator and a dot-dot filename, along with + // any immediately following directory separator. + {"foo/..", "."}, + {"foo/../", "."}, + {"foo/bar/..", "foo/"}, + {"foo/bar/../", "foo/"}, + {"foo/bar/../..", "."}, + {"foo/bar/../../", "."}, + {"foo/bar/baz/../..", "foo/"}, + {"foo/bar/baz/../../", "foo/"}, + {"foo/bar/./..", "foo/"}, + {"foo/bar/./../", "foo/"}, + // p6: If there is a root-directory, remove all dot-dot filenames and any + // directory-separators immediately following them. [ Note: These dot-dot + // filenames attempt to refer to nonexistent parent directories. — end note ] + {"/..", "/"}, + {"/../", "/"}, + {"/foo/../..", "/"}, + {"/../foo", "/foo"}, + {"/../foo/../..", "/"}, + // p7: If the last filename is dot-dot, remove any trailing + // directory-separator. + {"../", ".."}, + {"../../", "../.."}, + {"foo/../bar/../..///", ".."}, + {"foo/../bar/..//..///../", "../.."}, + // p8: If the path is empty, add a dot + {".", "."}, + {"./", "."}, + {"foo/..", "."} + }; + // clang-format on + int ID = 0; + bool Failed = false; + for (auto& TC : TestCases) { + ++ID; + fs::path p(TC.input); + const fs::path output = p.lexically_normal(); + if (!PathEq(output, TC.expect)) { + Failed = true; + std::cerr << "TEST CASE #" << ID << " FAILED: \n"; + std::cerr << " Input: '" << TC.input << "'\n"; + std::cerr << " Expected: '" << TC.expect << "'\n"; + std::cerr << " Output: '" << output.native() << "'"; + std::cerr << std::endl; + } + } + return Failed; +} diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp new file mode 100644 index 00000000000..8b56a19b716 --- /dev/null +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// <experimental/filesystem> + +// class path + +// path lexically_relative(const path& p) const; +// path lexically_proximate(const path& p) const; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <vector> +#include <iostream> +#include <cassert> + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + + +int main() { + // clang-format off + struct { + std::string input; + std::string base; + std::string expect; + } TestCases[] = { + {"", "", "."}, + {"/", "a", ""}, + {"a", "/", ""}, + {"//net", "a", ""}, + {"a", "//net", ""}, + {"//net/", "//net", ""}, + {"//net", "//net/", ".."}, + {"//base", "a", ""}, + {"a", "a", "."}, + {"a/b", "a/b", "."}, + {"a/b/c/", "a/b/c/", "."}, + {"//net", "//net", "."}, + {"//net/", "//net/", "."}, + {"//net/a/b", "//net/a/b", "."}, + {"/a/d", "/a/b/c", "../../d"}, + {"/a/b/c", "/a/d", "../b/c"}, + {"a/b/c", "a", "b/c"}, + {"a/b/c", "a/b/c/x/y", "../.."}, + {"a/b/c", "a/b/c", "."}, + {"a/b", "c/d", "../../a/b"} + }; + // clang-format on + int ID = 0; + bool Failed = false; + for (auto& TC : TestCases) { + ++ID; + const fs::path p(TC.input); + const fs::path output = p.lexically_relative(TC.base); + auto ReportErr = [&](const char* Testing, fs::path const& Output, + fs::path const& Expected) { + Failed = true; + std::cerr << "TEST CASE #" << ID << " FAILED: \n"; + std::cerr << " Testing: " << Testing << "\n"; + std::cerr << " Input: '" << TC.input << "'\n"; + std::cerr << " Base: '" << TC.base << "'\n"; + std::cerr << " Expected: '" << Expected << "'\n"; + std::cerr << " Output: '" << Output.native() << "'"; + std::cerr << std::endl; + }; + if (!PathEq(output, TC.expect)) + ReportErr("path::lexically_relative", output, TC.expect); + const fs::path proximate_output = p.lexically_proximate(TC.base); + // [path.gen] lexically_proximate + // Returns: If the value of lexically_relative(base) is not an empty path, + // return it.Otherwise return *this. + const fs::path proximate_expected = output.native().empty() ? p + : output; + if (!PathEq(proximate_expected, proximate_output)) + ReportErr("path::lexically_proximate", proximate_output, proximate_expected); + } + return Failed; +} diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp index 7e329376c93..a757cbb88fd 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp @@ -28,7 +28,6 @@ #include "min_allocator.h" #include "filesystem_test_helper.hpp" - MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp index d3df09ed97e..56b2787fbb6 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp @@ -30,7 +30,6 @@ #include "min_allocator.h" #include "filesystem_test_helper.hpp" - MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); int main() diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp index 84cdd521429..ec885f15c8c 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp @@ -23,7 +23,7 @@ #include "test_iterators.h" #include "count_new.hpp" #include "filesystem_test_helper.hpp" - +#include "verbose_assert.h" struct RemoveFilenameTestcase { const char* value; @@ -33,27 +33,29 @@ struct RemoveFilenameTestcase { const RemoveFilenameTestcase TestCases[] = { {"", ""} - , {"/", ""} - , {"//", ""} - , {"///", ""} + , {"/", "/"} + , {"//", "//"} + , {"///", "///"} , {"\\", ""} , {".", ""} , {"..", ""} , {"/foo", "/"} - , {"//foo", ""} - , {"//foo/", ""} - , {"//foo///", ""} - , {"///foo", "/"} - , {"///foo/", "///foo"} - , {"/foo/", "/foo"} - , {"/foo/.", "/foo"} - , {"/foo/..", "/foo"} - , {"/foo/////", "/foo"} + , {"foo/bar", "foo/"} + , {"foo/", "foo/"} + , {"//foo", "//"} + , {"//foo/", "//foo/"} + , {"//foo///", "//foo///"} + , {"///foo", "///"} + , {"///foo/", "///foo/"} + , {"/foo/", "/foo/"} + , {"/foo/.", "/foo/"} + , {"/foo/..", "/foo/"} + , {"/foo/////", "/foo/////"} , {"/foo\\\\", "/"} - , {"/foo//\\/", "/foo//\\"} - , {"///foo", "/"} + , {"/foo//\\/", "/foo//\\/"} + , {"///foo", "///"} , {"file.txt", ""} - , {"bar/../baz/./file.txt", "bar/../baz/."} + , {"bar/../baz/./file.txt", "bar/../baz/./"} }; int main() @@ -64,16 +66,8 @@ int main() path p(p_orig); assert(p == TC.value); path& Ref = (p.remove_filename()); - assert(p == TC.expect); + ASSERT_EQ(p, TC.expect) << DISPLAY(p_orig); assert(&Ref == &p); - { - const path parentp = p_orig.parent_path(); - if (parentp == p_orig.root_name()) { - - assert(p.empty()); - } else { - assert(p == parentp); - } - } + assert(!p.has_filename()); } } diff --git a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp index fb7741110cc..bfb3b6a19cd 100644 --- a/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp +++ b/libcxx/test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp @@ -23,7 +23,8 @@ #include "test_iterators.h" #include "count_new.hpp" #include "filesystem_test_helper.hpp" - +#include "assert_checkpoint.h" +#include "verbose_assert.h" struct ReplaceFilenameTestcase { const char* value; @@ -36,9 +37,9 @@ const ReplaceFilenameTestcase TestCases[] = {"/foo", "/bar", "bar"} , {"/foo", "/", ""} , {"foo", "bar", "bar"} - , {"/", "bar", "bar"} + , {"/", "/bar", "bar"} , {"\\", "bar", "bar"} - , {"///", "bar", "bar"} + , {"///", "///bar", "bar"} , {"\\\\", "bar", "bar"} , {"\\/\\", "\\/bar", "bar"} , {".", "bar", "bar"} @@ -52,9 +53,11 @@ int main() using namespace fs; for (auto const & TC : TestCases) { path p(TC.value); - assert(p == TC.value); + ASSERT_EQ(p, TC.value); path& Ref = (p.replace_filename(TC.filename)); - assert(p == TC.expect); + ASSERT_EQ(p, TC.expect) + << DISPLAY(TC.value) + << DISPLAY(TC.filename); assert(&Ref == &p); // Tests Effects "as-if": remove_filename() append(filename) { @@ -62,7 +65,7 @@ int main() path replace(TC.filename); p2.remove_filename(); p2 /= replace; - assert(p2 == p); + ASSERT_EQ(p, p2); } } } |