summaryrefslogtreecommitdiffstats
path: root/libcxx/test/std/input.output/filesystems/class.path
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/test/std/input.output/filesystems/class.path')
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.itr/iterator.pass.cpp106
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp340
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/braced_init.pass.cpp32
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/copy.pass.cpp37
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp43
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/source.pass.cpp242
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp192
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp389
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/copy.pass.cpp35
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/default.pass.cpp31
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp41
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp130
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/empty.fail.cpp29
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/path.decompose.pass.cpp217
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_normal.pass.cpp141
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp88
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp56
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp62
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/clear.pass.cpp45
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/make_preferred.pass.cpp55
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/remove_filename.pass.cpp74
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_extension.pass.cpp73
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_filename.pass.cpp72
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/swap.pass.cpp81
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/c_str.pass.cpp43
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp63
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/native.pass.cpp40
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/operator_string.pass.cpp47
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/string_alloc.pass.cpp138
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp33
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.fail.cpp28
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.pass.cpp35
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops.fail.cpp34
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp15
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp15
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp53
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.pass.cpp99
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.unicode_bug.pass.cpp70
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.nonmember/swap.pass.cpp50
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/synop.pass.cpp39
40 files changed, 3413 insertions, 0 deletions
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.itr/iterator.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.itr/iterator.pass.cpp
new file mode 100644
index 00000000000..558206d7082
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.itr/iterator.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class Source>
+// path(const Source& source);
+// template <class InputIterator>
+// path(InputIterator first, InputIterator last);
+
+
+#include "filesystem_include.hpp"
+#include <iterator>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+
+
+template <class It>
+std::reverse_iterator<It> mkRev(It it) {
+ return std::reverse_iterator<It>(it);
+}
+
+void checkIteratorConcepts() {
+ using namespace fs;
+ using It = path::iterator;
+ using Traits = std::iterator_traits<It>;
+ ASSERT_SAME_TYPE(Traits::iterator_category, std::bidirectional_iterator_tag);
+ ASSERT_SAME_TYPE(Traits::value_type, path);
+ ASSERT_SAME_TYPE(Traits::pointer, path const*);
+ ASSERT_SAME_TYPE(Traits::reference, path const&);
+ {
+ It it;
+ ASSERT_SAME_TYPE(It&, decltype(++it));
+ ASSERT_SAME_TYPE(It, decltype(it++));
+ ASSERT_SAME_TYPE(It&, decltype(--it));
+ ASSERT_SAME_TYPE(It, decltype(it--));
+ ASSERT_SAME_TYPE(Traits::reference, decltype(*it));
+ ASSERT_SAME_TYPE(Traits::pointer, decltype(it.operator->()));
+ ASSERT_SAME_TYPE(std::string const&, decltype(it->native()));
+ ASSERT_SAME_TYPE(bool, decltype(it == it));
+ ASSERT_SAME_TYPE(bool, decltype(it != it));
+ }
+ {
+ path const p;
+ ASSERT_SAME_TYPE(It, decltype(p.begin()));
+ ASSERT_SAME_TYPE(It, decltype(p.end()));
+ assert(p.begin() == p.end());
+ }
+}
+
+void checkBeginEndBasic() {
+ using namespace fs;
+ using It = path::iterator;
+ {
+ path const p;
+ ASSERT_SAME_TYPE(It, decltype(p.begin()));
+ ASSERT_SAME_TYPE(It, decltype(p.end()));
+ assert(p.begin() == p.end());
+ }
+ {
+ path const p("foo");
+ It default_constructed;
+ default_constructed = p.begin();
+ assert(default_constructed == p.begin());
+ assert(default_constructed != p.end());
+ default_constructed = p.end();
+ assert(default_constructed == p.end());
+ assert(default_constructed != p.begin());
+ }
+ {
+ path p("//root_name//first_dir////second_dir");
+ const path expect[] = {"/", "root_name", "first_dir", "second_dir"};
+ assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
+ assert(checkCollectionsEqualBackwards(p.begin(), p.end(), std::begin(expect), std::end(expect)));
+
+ }
+ {
+ path p("////foo/bar/baz///");
+ const path expect[] = {"/", "foo", "bar", "baz", ""};
+ assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
+ assert(checkCollectionsEqualBackwards(p.begin(), p.end(), std::begin(expect), std::end(expect)));
+
+ }
+
+}
+
+int main(int, char**) {
+ using namespace fs;
+ checkIteratorConcepts();
+ checkBeginEndBasic(); // See path.decompose.pass.cpp for more tests.
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
new file mode 100644
index 00000000000..2f468e59554
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
@@ -0,0 +1,340 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& operator/=(path const&)
+// template <class Source>
+// path& operator/=(Source const&);
+// template <class Source>
+// path& append(Source const&);
+// template <class InputIterator>
+// path& append(InputIterator first, InputIterator last);
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <string_view>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+#include "verbose_assert.h"
+
+
+struct AppendOperatorTestcase {
+ MultiStringType lhs;
+ MultiStringType rhs;
+ MultiStringType expect;
+};
+
+#define S(Str) MKSTR(Str)
+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("/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(""), 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/")}
+ };
+
+
+const AppendOperatorTestcase LongLHSCases[] =
+ {
+ {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
+
+
+// The append operator may need to allocate a temporary buffer before a code_cvt
+// conversion. Test if this allocation occurs by:
+// 1. Create a path, `LHS`, and reserve enough space to append `RHS`.
+// This prevents `LHS` from allocating during the actual appending.
+// 2. Create a `Source` object `RHS`, which represents a "large" string.
+// (The string must not trigger the SSO)
+// 3. Append `RHS` to `LHS` and check for the expected allocation behavior.
+template <class CharT>
+void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
+{
+ using namespace fs;
+ using Ptr = CharT const*;
+ using Str = std::basic_string<CharT>;
+ using StrView = std::basic_string_view<CharT>;
+ using InputIter = input_iterator<Ptr>;
+
+ const Ptr L = TC.lhs;
+ Str RShort = (Ptr)TC.rhs;
+ Str EShort = (Ptr)TC.expect;
+ assert(RShort.size() >= 2);
+ CharT c = RShort.back();
+ RShort.append(100, c);
+ EShort.append(100, c);
+ const Ptr R = RShort.data();
+ const Str& E = EShort;
+ std::size_t ReserveSize = E.size() + 3;
+ // basic_string
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ Str RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS /= RHS;
+ }
+ ASSERT_PRED(PathEq, LHS , E);
+ }
+ // basic_string_view
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ StrView RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS /= RHS;
+ }
+ assert(PathEq(LHS, E));
+ }
+ // CharT*
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ Ptr RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS /= RHS;
+ }
+ assert(PathEq(LHS, E));
+ }
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ Ptr RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS.append(RHS, StrEnd(RHS));
+ }
+ 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
+ // code_cvt conversions.
+ // For "char" no allocations will be performed because no conversion is
+ // required.
+ bool DisableAllocations = std::is_same<CharT, char>::value;
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ InputIter RHS(R);
+ {
+ RequireAllocationGuard g; // requires 1 or more allocations occur by default
+ if (DisableAllocations) g.requireExactly(0);
+ LHS /= RHS;
+ }
+ assert(PathEq(LHS, E));
+ }
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ InputIter RHS(R);
+ InputIter REnd(StrEnd(R));
+ {
+ RequireAllocationGuard g;
+ if (DisableAllocations) g.requireExactly(0);
+ LHS.append(RHS, REnd);
+ }
+ assert(PathEq(LHS, E));
+ }
+}
+
+template <class CharT>
+void doAppendSourceTest(AppendOperatorTestcase const& TC)
+{
+ using namespace fs;
+ using Ptr = CharT const*;
+ using Str = std::basic_string<CharT>;
+ using StrView = std::basic_string_view<CharT>;
+ using InputIter = input_iterator<Ptr>;
+ const Ptr L = TC.lhs;
+ const Ptr R = TC.rhs;
+ const Ptr E = TC.expect;
+ // basic_string
+ {
+ path Result(L);
+ Str RHS(R);
+ 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(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+ // basic_string_view
+ {
+ path LHS(L);
+ StrView RHS(R);
+ path& Ref = (LHS /= RHS);
+ assert(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ StrView RHS(R);
+ path& Ref = LHS.append(RHS);
+ assert(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+ // Char*
+ {
+ path LHS(L);
+ Str RHS(R);
+ path& Ref = (LHS /= RHS);
+ assert(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ Ptr RHS(R);
+ path& Ref = LHS.append(RHS);
+ assert(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ Ptr RHS(R);
+ path& Ref = LHS.append(RHS, StrEnd(RHS));
+ ASSERT_PRED(PathEq, LHS, E)
+ << DISPLAY(L) << DISPLAY(R);
+ assert(&Ref == &LHS);
+ }
+ // iterators
+ {
+ path LHS(L);
+ InputIter RHS(R);
+ path& Ref = (LHS /= RHS);
+ assert(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L); InputIter RHS(R);
+ path& Ref = LHS.append(RHS);
+ assert(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ InputIter RHS(R);
+ InputIter REnd(StrEnd(R));
+ path& Ref = LHS.append(RHS, REnd);
+ assert(PathEq(LHS, E));
+ assert(&Ref == &LHS);
+ }
+}
+
+
+
+template <class It, class = decltype(fs::path{}.append(std::declval<It>()))>
+constexpr bool has_append(int) { return true; }
+template <class It>
+constexpr bool has_append(long) { return false; }
+
+template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))>
+constexpr bool has_append_op(int) { return true; }
+template <class It>
+constexpr bool has_append_op(long) { return false; }
+
+template <class It>
+constexpr bool has_append() {
+ static_assert(has_append<It>(0) == has_append_op<It>(0), "must be same");
+ return has_append<It>(0) && has_append_op<It>(0);
+}
+
+void test_sfinae()
+{
+ using namespace fs;
+ {
+ using It = const char* const;
+ static_assert(has_append<It>(), "");
+ }
+ {
+ using It = input_iterator<const char*>;
+ static_assert(has_append<It>(), "");
+ }
+ {
+ struct Traits {
+ using iterator_category = std::input_iterator_tag;
+ using value_type = const char;
+ using pointer = const char*;
+ using reference = const char&;
+ using difference_type = std::ptrdiff_t;
+ };
+ using It = input_iterator<const char*, Traits>;
+ static_assert(has_append<It>(), "");
+ }
+ {
+ using It = output_iterator<const char*>;
+ static_assert(!has_append<It>(), "");
+
+ }
+ {
+ static_assert(!has_append<int*>(), "");
+ }
+ {
+ static_assert(!has_append<char>(), "");
+ static_assert(!has_append<const char>(), "");
+ }
+}
+
+int main(int, char**)
+{
+ using namespace fs;
+ for (auto const & TC : Cases) {
+ {
+ 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);
+ doAppendSourceTest<char16_t>(TC);
+ doAppendSourceTest<char32_t>(TC);
+ }
+ for (auto const & TC : LongLHSCases) {
+ doAppendSourceAllocTest<char>(TC);
+ doAppendSourceAllocTest<wchar_t>(TC);
+ }
+ test_sfinae();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/braced_init.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/braced_init.pass.cpp
new file mode 100644
index 00000000000..aff89f27bd3
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/braced_init.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& operator=(path const&);
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+
+
+int main(int, char**) {
+ using namespace fs;
+ path p("abc");
+ p = {};
+ assert(p.native() == "");
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/copy.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/copy.pass.cpp
new file mode 100644
index 00000000000..9265c70f6f4
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/copy.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& operator=(path const&);
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+
+int main(int, char**) {
+ using namespace fs;
+ static_assert(std::is_copy_assignable<path>::value, "");
+ static_assert(!std::is_nothrow_copy_assignable<path>::value, "should not be noexcept");
+ const std::string s("foo");
+ const path p(s);
+ path p2;
+ path& pref = (p2 = p);
+ assert(p.native() == s);
+ assert(p2.native() == s);
+ assert(&pref == &p2);
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp
new file mode 100644
index 00000000000..5e5fb1e0e06
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& operator=(path&&) noexcept
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+
+
+int main(int, char**) {
+ using namespace fs;
+ static_assert(std::is_nothrow_move_assignable<path>::value, "");
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+ const std::string s("we really really really really really really really "
+ "really really long string so that we allocate");
+ assert(globalMemCounter.checkOutstandingNewEq(1));
+ path p(s);
+ {
+ DisableAllocationGuard g;
+ path p2;
+ path& pref = (p2 = std::move(p));
+ assert(p2.native() == s);
+ assert(p.native() != s); // Testing moved from state
+ assert(&pref == &p2);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/source.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/source.pass.cpp
new file mode 100644
index 00000000000..9c23e3b3ebf
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/source.pass.cpp
@@ -0,0 +1,242 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class Source>
+// path& operator=(Source const&);
+// path& operator=(string_type&&);
+// template <class Source>
+// path& assign(Source const&);
+// template <class InputIterator>
+// path& assign(InputIterator first, InputIterator last);
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <string_view>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+#include <iostream>
+
+
+template <class CharT>
+void RunTestCase(MultiStringType const& MS) {
+ using namespace fs;
+ const char* Expect = MS;
+ const CharT* TestPath = MS;
+ const CharT* TestPathEnd = StrEnd(TestPath);
+ const std::size_t Size = TestPathEnd - TestPath;
+ const std::size_t SSize = StrEnd(Expect) - Expect;
+ assert(Size == SSize);
+ //////////////////////////////////////////////////////////////////////////////
+ // basic_string<Char, Traits, Alloc>
+ {
+ const std::basic_string<CharT> S(TestPath);
+ path p; PathReserve(p, S.length() + 1);
+ {
+ // string provides a contiguous iterator. No allocation needed.
+ DisableAllocationGuard g;
+ path& pref = (p = S);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ assert(p.string<CharT>() == S);
+ }
+ {
+ const std::basic_string<CharT> S(TestPath);
+ path p; PathReserve(p, S.length() + 1);
+ {
+ DisableAllocationGuard g;
+ path& pref = p.assign(S);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ assert(p.string<CharT>() == S);
+ }
+ // basic_string<Char, Traits, Alloc>
+ {
+ const std::basic_string_view<CharT> S(TestPath);
+ path p; PathReserve(p, S.length() + 1);
+ {
+ // string provides a contiguous iterator. No allocation needed.
+ DisableAllocationGuard g;
+ path& pref = (p = S);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ assert(p.string<CharT>() == S);
+ }
+ {
+ const std::basic_string_view<CharT> S(TestPath);
+ path p; PathReserve(p, S.length() + 1);
+ {
+ DisableAllocationGuard g;
+ path& pref = p.assign(S);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ assert(p.string<CharT>() == S);
+ }
+ //////////////////////////////////////////////////////////////////////////////
+ // Char* pointers
+ {
+ path p; PathReserve(p, Size + 1);
+ {
+ // char* pointers are contiguous and can be used with code_cvt directly.
+ // no allocations needed.
+ DisableAllocationGuard g;
+ path& pref = (p = TestPath);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ {
+ path p; PathReserve(p, Size + 1);
+ {
+ DisableAllocationGuard g;
+ path& pref = p.assign(TestPath);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ {
+ path p; PathReserve(p, Size + 1);
+ {
+ DisableAllocationGuard g;
+ path& pref = p.assign(TestPath, TestPathEnd);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ //////////////////////////////////////////////////////////////////////////////
+ // Iterators
+ {
+ using It = input_iterator<const CharT*>;
+ path p; PathReserve(p, Size + 1);
+ It it(TestPath);
+ {
+ // Iterators cannot be used with code_cvt directly. This assignment
+ // may allocate if it's larger than a "short-string".
+ path& pref = (p = it);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ {
+ using It = input_iterator<const CharT*>;
+ path p; PathReserve(p, Size + 1);
+ It it(TestPath);
+ {
+ path& pref = p.assign(it);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ {
+ using It = input_iterator<const CharT*>;
+ path p; PathReserve(p, Size + 1);
+ It it(TestPath);
+ It e(TestPathEnd);
+ {
+ path& pref = p.assign(it, e);
+ assert(&pref == &p);
+ }
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+}
+
+template <class It, class = decltype(fs::path{}.assign(std::declval<It>()))>
+constexpr bool has_assign(int) { return true; }
+template <class It>
+constexpr bool has_assign(long) { return false; }
+template <class It>
+constexpr bool has_assign() { return has_assign<It>(0); }
+
+void test_sfinae() {
+ using namespace fs;
+ {
+ using It = const char* const;
+ static_assert(std::is_assignable<path, It>::value, "");
+ static_assert(has_assign<It>(), "");
+ }
+ {
+ using It = input_iterator<const char*>;
+ static_assert(std::is_assignable<path, It>::value, "");
+ static_assert(has_assign<It>(), "");
+ }
+ {
+ struct Traits {
+ using iterator_category = std::input_iterator_tag;
+ using value_type = const char;
+ using pointer = const char*;
+ using reference = const char&;
+ using difference_type = std::ptrdiff_t;
+ };
+ using It = input_iterator<const char*, Traits>;
+ static_assert(std::is_assignable<path, It>::value, "");
+ static_assert(has_assign<It>(), "");
+ }
+ {
+ using It = output_iterator<const char*>;
+ static_assert(!std::is_assignable<path, It>::value, "");
+ static_assert(!has_assign<It>(), "");
+
+ }
+ {
+ static_assert(!std::is_assignable<path, int*>::value, "");
+ static_assert(!has_assign<int*>(), "");
+ }
+}
+
+void RunStringMoveTest(const char* Expect) {
+ using namespace fs;
+ std::string ss(Expect);
+ path p;
+ {
+ DisableAllocationGuard g; ((void)g);
+ path& pr = (p = std::move(ss));
+ assert(&pr == &p);
+ }
+ assert(p == Expect);
+ {
+ // Signature test
+ ASSERT_NOEXCEPT(p = std::move(ss));
+ }
+}
+
+int main(int, char**) {
+ for (auto const& MS : PathList) {
+ RunTestCase<char>(MS);
+ RunTestCase<wchar_t>(MS);
+ RunTestCase<char16_t>(MS);
+ RunTestCase<char32_t>(MS);
+ RunStringMoveTest(MS);
+ }
+ test_sfinae();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
new file mode 100644
index 00000000000..165e62fe4fe
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
@@ -0,0 +1,192 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// int compare(path const&) const noexcept;
+// int compare(string_type const&) const;
+// int compare(value_type const*) const;
+//
+// bool operator==(path const&, path const&) noexcept;
+// bool operator!=(path const&, path const&) noexcept;
+// bool operator< (path const&, path const&) noexcept;
+// bool operator<=(path const&, path const&) noexcept;
+// bool operator> (path const&, path const&) noexcept;
+// bool operator>=(path const&, path const&) noexcept;
+//
+// size_t hash_value(path const&) noexcept;
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <vector>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+#include "verbose_assert.h"
+
+struct PathCompareTest {
+ const char* LHS;
+ const char* RHS;
+ int expect;
+};
+
+#define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+#define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+#define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
+#define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
+const PathCompareTest CompareTestCases[] =
+{
+ {"", "", 0},
+ {"a", "", 1},
+ {"", "a", -1},
+ {"a/b/c", "a/b/c", 0},
+ {"b/a/c", "a/b/c", 1},
+ {"a/b/c", "b/a/c", -1},
+ {"a/b", "a/b/c", -1},
+ {"a/b/c", "a/b", 1},
+ {"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
+ {"/foo/bar/", "/foo/bar", 1}, // trailing separator
+ {"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0.
+ {"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0.
+ {"//" LONGA "////" LONGB "/" LONGC "///" LONGD, "//" LONGA "/" LONGB "/" LONGC "/" LONGD, 0},
+ { LONGA "/" LONGB "/" LONGC, LONGA "/" LONGB "/" LONGB, 1}
+
+};
+#undef LONGA
+#undef LONGB
+#undef LONGC
+#undef LONGD
+
+static inline int normalize_ret(int ret)
+{
+ return ret < 0 ? -1 : (ret > 0 ? 1 : 0);
+}
+
+void test_compare_basic()
+{
+ using namespace fs;
+ for (auto const & TC : CompareTestCases) {
+ const path p1(TC.LHS);
+ const path p2(TC.RHS);
+ const std::string R(TC.RHS);
+ const std::string_view RV(TC.RHS);
+ const int E = TC.expect;
+ { // compare(...) functions
+ DisableAllocationGuard g; // none of these operations should allocate
+
+ // check runtime results
+ int ret1 = normalize_ret(p1.compare(p2));
+ int ret2 = normalize_ret(p1.compare(R));
+ int ret3 = normalize_ret(p1.compare(TC.RHS));
+ int ret4 = normalize_ret(p1.compare(RV));
+
+ 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));
+ }
+ { // comparison operators
+ DisableAllocationGuard g; // none of these operations should allocate
+
+ // Check runtime result
+ assert((p1 == p2) == (E == 0));
+ assert((p1 != p2) == (E != 0));
+ assert((p1 < p2) == (E < 0));
+ assert((p1 <= p2) == (E <= 0));
+ assert((p1 > p2) == (E > 0));
+ assert((p1 >= p2) == (E >= 0));
+
+ // Check signatures
+ ASSERT_NOEXCEPT(p1 == p2);
+ ASSERT_NOEXCEPT(p1 != p2);
+ ASSERT_NOEXCEPT(p1 < p2);
+ ASSERT_NOEXCEPT(p1 <= p2);
+ ASSERT_NOEXCEPT(p1 > p2);
+ ASSERT_NOEXCEPT(p1 >= p2);
+ }
+ { // check hash values
+ auto h1 = hash_value(p1);
+ auto h2 = hash_value(p2);
+ assert((h1 == h2) == (p1 == p2));
+ // check signature
+ ASSERT_SAME_TYPE(size_t, decltype(hash_value(p1)));
+ ASSERT_NOEXCEPT(hash_value(p1));
+ }
+ }
+}
+
+int CompareElements(std::vector<std::string> const& LHS, std::vector<std::string> const& RHS) {
+ bool IsLess = std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(), RHS.end());
+ if (IsLess)
+ return -1;
+
+ bool IsGreater = std::lexicographical_compare(RHS.begin(), RHS.end(), LHS.begin(), LHS.end());
+ if (IsGreater)
+ return 1;
+
+ return 0;
+}
+
+void test_compare_elements() {
+ struct {
+ std::vector<std::string> LHSElements;
+ std::vector<std::string> RHSElements;
+ int Expect;
+ } TestCases[] = {
+ {{"a"}, {"a"}, 0},
+ {{"a"}, {"b"}, -1},
+ {{"b"}, {"a"}, 1},
+ {{"a", "b", "c"}, {"a", "b", "c"}, 0},
+ {{"a", "b", "c"}, {"a", "b", "d"}, -1},
+ {{"a", "b", "d"}, {"a", "b", "c"}, 1},
+ {{"a", "b"}, {"a", "b", "c"}, -1},
+ {{"a", "b", "c"}, {"a", "b"}, 1},
+
+ };
+
+ auto BuildPath = [](std::vector<std::string> const& Elems) {
+ fs::path p;
+ for (auto &E : Elems)
+ p /= E;
+ return p;
+ };
+
+ for (auto &TC : TestCases) {
+ fs::path LHS = BuildPath(TC.LHSElements);
+ fs::path RHS = BuildPath(TC.RHSElements);
+ const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements);
+ assert(ExpectCmp == TC.Expect);
+ const int GotCmp = normalize_ret(LHS.compare(RHS));
+ assert(GotCmp == TC.Expect);
+ }
+}
+
+int main(int, char**) {
+ test_compare_basic();
+ test_compare_elements();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
new file mode 100644
index 00000000000..b074e831e15
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
@@ -0,0 +1,389 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& operator+=(const path& x);
+// path& operator+=(const string_type& x);
+// path& operator+=(string_view x);
+// path& operator+=(const value_type* x);
+// path& operator+=(value_type x);
+// template <class Source>
+// path& operator+=(const Source& x);
+// template <class EcharT>
+// path& operator+=(EcharT x);
+// template <class Source>
+// path& concat(const Source& x);
+// template <class InputIterator>
+// path& concat(InputIterator first, InputIterator last);
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <string>
+#include <string_view>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+
+struct ConcatOperatorTestcase {
+ MultiStringType lhs;
+ MultiStringType rhs;
+ MultiStringType expect;
+};
+
+#define LONGSTR "LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR"
+#define S(Str) MKSTR(Str)
+const ConcatOperatorTestcase Cases[] =
+ {
+ {S(""), S(""), S("")}
+ , {S("p1"), S("p2"), S("p1p2")}
+ , {S("p1/"), S("/p2"), S("p1//p2")}
+ , {S(""), S("\\foo/bar/baz"), S("\\foo/bar/baz")}
+ , {S("c:\\foo"), S(""), S("c:\\foo")}
+ , {S(LONGSTR), S("foo"), S(LONGSTR "foo")}
+ , {S("abcdefghijklmnopqrstuvwxyz/\\"), S("/\\123456789"), S("abcdefghijklmnopqrstuvwxyz/\\/\\123456789")}
+ };
+const ConcatOperatorTestcase LongLHSCases[] =
+ {
+ {S(""), S(LONGSTR), S(LONGSTR)}
+ , {S("p1/"), S(LONGSTR), S("p1/" LONGSTR)}
+ };
+const ConcatOperatorTestcase CharTestCases[] =
+ {
+ {S(""), S("P"), S("P")}
+ , {S("/fooba"), S("r"), S("/foobar")}
+ };
+#undef S
+#undef LONGSTR
+
+// The concat operator may need to allocate a temporary buffer before a code_cvt
+// conversion. Test if this allocation occurs by:
+// 1. Create a path, `LHS`, and reserve enough space to append `RHS`.
+// This prevents `LHS` from allocating during the actual appending.
+// 2. Create a `Source` object `RHS`, which represents a "large" string.
+// (The string must not trigger the SSO)
+// 3. Concat `RHS` to `LHS` and check for the expected allocation behavior.
+template <class CharT>
+void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC)
+{
+ using namespace fs;
+ using Ptr = CharT const*;
+ using Str = std::basic_string<CharT>;
+ using StrView = std::basic_string_view<CharT>;
+ using InputIter = input_iterator<Ptr>;
+
+ const Ptr L = TC.lhs;
+ const Ptr R = TC.rhs;
+ const Ptr E = TC.expect;
+ std::size_t ReserveSize = StrLen(E) + 1;
+ // basic_string
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ Str RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS += RHS;
+ }
+ assert(LHS == E);
+ }
+ // basic_string_view
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ StrView RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS += RHS;
+ }
+ assert(LHS == E);
+ }
+ // CharT*
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ Ptr RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS += RHS;
+ }
+ assert(LHS == E);
+ }
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ Ptr RHS(R);
+ {
+ DisableAllocationGuard g;
+ LHS.concat(RHS, StrEnd(RHS));
+ }
+ assert(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
+ // code_cvt conversions.
+ // For "char" no allocations will be performed because no conversion is
+ // required.
+ bool DisableAllocations = std::is_same<CharT, char>::value;
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ InputIter RHS(R);
+ {
+ RequireAllocationGuard g; // requires 1 or more allocations occur by default
+ if (DisableAllocations) g.requireExactly(0);
+ LHS += RHS;
+ }
+ assert(LHS == E);
+ }
+ {
+ path LHS(L); PathReserve(LHS, ReserveSize);
+ InputIter RHS(R);
+ InputIter REnd(StrEnd(R));
+ {
+ RequireAllocationGuard g;
+ if (DisableAllocations) g.requireExactly(0);
+ LHS.concat(RHS, REnd);
+ }
+ assert(LHS == E);
+ }
+}
+
+template <class CharT>
+void doConcatSourceTest(ConcatOperatorTestcase const& TC)
+{
+ using namespace fs;
+ using Ptr = CharT const*;
+ using Str = std::basic_string<CharT>;
+ using StrView = std::basic_string_view<CharT>;
+ using InputIter = input_iterator<Ptr>;
+ const Ptr L = TC.lhs;
+ const Ptr R = TC.rhs;
+ const Ptr E = TC.expect;
+ // basic_string
+ {
+ path LHS(L);
+ Str RHS(R);
+ path& Ref = (LHS += RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ Str RHS(R);
+ path& Ref = LHS.concat(RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ // basic_string_view
+ {
+ path LHS(L);
+ StrView RHS(R);
+ path& Ref = (LHS += RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ StrView RHS(R);
+ path& Ref = LHS.concat(RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ // Char*
+ {
+ path LHS(L);
+ Str RHS(R);
+ path& Ref = (LHS += RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ Ptr RHS(R);
+ path& Ref = LHS.concat(RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ Ptr RHS(R);
+ path& Ref = LHS.concat(RHS, StrEnd(RHS));
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ // iterators
+ {
+ path LHS(L);
+ InputIter RHS(R);
+ path& Ref = (LHS += RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L); InputIter RHS(R);
+ path& Ref = LHS.concat(RHS);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+ {
+ path LHS(L);
+ InputIter RHS(R);
+ InputIter REnd(StrEnd(R));
+ path& Ref = LHS.concat(RHS, REnd);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+}
+
+template <class CharT>
+void doConcatECharTest(ConcatOperatorTestcase const& TC)
+{
+ using namespace fs;
+ using Ptr = CharT const*;
+ const Ptr RStr = TC.rhs;
+ assert(StrLen(RStr) == 1);
+ const Ptr L = TC.lhs;
+ const CharT R = RStr[0];
+ const Ptr E = TC.expect;
+ {
+ path LHS(L);
+ path& Ref = (LHS += R);
+ assert(LHS == E);
+ assert(&Ref == &LHS);
+ }
+}
+
+
+template <class It, class = decltype(fs::path{}.concat(std::declval<It>()))>
+constexpr bool has_concat(int) { return true; }
+template <class It>
+constexpr bool has_concat(long) { return false; }
+
+template <class It, class = decltype(fs::path{}.operator+=(std::declval<It>()))>
+constexpr bool has_concat_op(int) { return true; }
+template <class It>
+constexpr bool has_concat_op(long) { return false; }
+template <class It>
+constexpr bool has_concat_op() { return has_concat_op<It>(0); }
+
+template <class It>
+constexpr bool has_concat() {
+ static_assert(has_concat<It>(0) == has_concat_op<It>(0), "must be same");
+ return has_concat<It>(0) && has_concat_op<It>(0);
+}
+
+void test_sfinae() {
+ using namespace fs;
+ {
+ static_assert(has_concat_op<char>(), "");
+ static_assert(has_concat_op<const char>(), "");
+ static_assert(has_concat_op<char16_t>(), "");
+ static_assert(has_concat_op<const char16_t>(), "");
+ }
+ {
+ using It = const char* const;
+ static_assert(has_concat<It>(), "");
+ }
+ {
+ using It = input_iterator<const char*>;
+ static_assert(has_concat<It>(), "");
+ }
+ {
+ struct Traits {
+ using iterator_category = std::input_iterator_tag;
+ using value_type = const char;
+ using pointer = const char*;
+ using reference = const char&;
+ using difference_type = std::ptrdiff_t;
+ };
+ using It = input_iterator<const char*, Traits>;
+ static_assert(has_concat<It>(), "");
+ }
+ {
+ using It = output_iterator<const char*>;
+ static_assert(!has_concat<It>(), "");
+ }
+ {
+ static_assert(!has_concat<int>(0), "");
+ // operator+=(int) is well formed since it converts to operator+=(value_type)
+ // but concat(int) isn't valid because there is no concat(value_type).
+ // This should probably be addressed by a LWG issue.
+ static_assert(has_concat_op<int>(), "");
+ }
+ {
+ static_assert(!has_concat<int*>(), "");
+ }
+}
+
+int main(int, char**)
+{
+ 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);
+ }
+ {
+ path LHS((const char*)TC.lhs);
+ std::string_view RHS((const char*)TC.rhs);
+ path& Ref = (LHS += RHS);
+ assert(LHS == (const char*)TC.expect);
+ assert(&Ref == &LHS);
+ }
+ doConcatSourceTest<char> (TC);
+ doConcatSourceTest<wchar_t> (TC);
+ doConcatSourceTest<char16_t>(TC);
+ doConcatSourceTest<char32_t>(TC);
+ }
+ for (auto const & TC : LongLHSCases) {
+ // Do path test
+ {
+ path LHS((const char*)TC.lhs);
+ path RHS((const char*)TC.rhs);
+ const char* E = TC.expect;
+ PathReserve(LHS, StrLen(E) + 5);
+ {
+ DisableAllocationGuard g;
+ path& Ref = (LHS += RHS);
+ assert(&Ref == &LHS);
+ }
+ assert(LHS == E);
+ }
+ {
+ path LHS((const char*)TC.lhs);
+ std::string_view RHS((const char*)TC.rhs);
+ const char* E = TC.expect;
+ PathReserve(LHS, StrLen(E) + 5);
+ {
+ DisableAllocationGuard g;
+ path& Ref = (LHS += RHS);
+ assert(&Ref == &LHS);
+ }
+ assert(LHS == E);
+ }
+ doConcatSourceAllocTest<char>(TC);
+ doConcatSourceAllocTest<wchar_t>(TC);
+ }
+ for (auto const& TC : CharTestCases) {
+ doConcatECharTest<char>(TC);
+ doConcatECharTest<wchar_t>(TC);
+ doConcatECharTest<char16_t>(TC);
+ doConcatECharTest<char32_t>(TC);
+ }
+ test_sfinae();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/copy.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/copy.pass.cpp
new file mode 100644
index 00000000000..1490c0b9fed
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/copy.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path(path const&)
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+
+int main(int, char**) {
+ using namespace fs;
+ static_assert(std::is_copy_constructible<path>::value, "");
+ static_assert(!std::is_nothrow_copy_constructible<path>::value, "should not be noexcept");
+ const std::string s("foo");
+ const path p(s);
+ path p2(p);
+ assert(p.native() == s);
+ assert(p2.native() == s);
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/default.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/default.pass.cpp
new file mode 100644
index 00000000000..b31728da1f9
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/default.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path() noexcept
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+
+int main(int, char**) {
+ using namespace fs;
+ static_assert(std::is_nothrow_default_constructible<path>::value, "");
+ const path p;
+ assert(p.empty());
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp
new file mode 100644
index 00000000000..494a77c3c86
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path(path&&) noexcept
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+
+
+int main(int, char**) {
+ using namespace fs;
+ static_assert(std::is_nothrow_move_constructible<path>::value, "");
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+ const std::string s("we really really really really really really really "
+ "really really long string so that we allocate");
+ assert(globalMemCounter.checkOutstandingNewEq(1));
+ path p(s);
+ {
+ DisableAllocationGuard g;
+ path p2(std::move(p));
+ assert(p2.native() == s);
+ assert(p.native() != s); // Testing moved from state
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp
new file mode 100644
index 00000000000..bcb9986cec9
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp
@@ -0,0 +1,130 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class Source>
+// path(const Source& source);
+// template <class InputIterator>
+// path(InputIterator first, InputIterator last);
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+
+template <class CharT, class ...Args>
+void RunTestCaseImpl(MultiStringType const& MS, Args... args) {
+ using namespace fs;
+ const char* Expect = MS;
+ const CharT* TestPath = MS;
+ const CharT* TestPathEnd = StrEnd(TestPath);
+ const std::size_t Size = TestPathEnd - TestPath;
+ const std::size_t SSize = StrEnd(Expect) - Expect;
+ assert(Size == SSize);
+ // StringTypes
+ {
+ const std::basic_string<CharT> S(TestPath);
+ path p(S, args...);
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ assert(p.string<CharT>() == S);
+ }
+ {
+ const std::basic_string_view<CharT> S(TestPath);
+ path p(S, args...);
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ assert(p.string<CharT>() == S);
+ }
+ // Char* pointers
+ {
+ path p(TestPath, args...);
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ {
+ path p(TestPath, TestPathEnd, args...);
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ // Iterators
+ {
+ using It = input_iterator<const CharT*>;
+ path p(It{TestPath}, args...);
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+ {
+ using It = input_iterator<const CharT*>;
+ path p(It{TestPath}, It{TestPathEnd}, args...);
+ assert(p.native() == Expect);
+ assert(p.string<CharT>() == TestPath);
+ }
+}
+
+template <class CharT, class ...Args>
+void RunTestCase(MultiStringType const& MS) {
+ RunTestCaseImpl<CharT>(MS);
+ RunTestCaseImpl<CharT>(MS, fs::path::format::auto_format);
+ RunTestCaseImpl<CharT>(MS, fs::path::format::native_format);
+ RunTestCaseImpl<CharT>(MS, fs::path::format::generic_format);
+}
+
+void test_sfinae() {
+ using namespace fs;
+ {
+ using It = const char* const;
+ static_assert(std::is_constructible<path, It>::value, "");
+ }
+ {
+ using It = input_iterator<const char*>;
+ static_assert(std::is_constructible<path, It>::value, "");
+ }
+ {
+ struct Traits {
+ using iterator_category = std::input_iterator_tag;
+ using value_type = const char;
+ using pointer = const char*;
+ using reference = const char&;
+ using difference_type = std::ptrdiff_t;
+ };
+ using It = input_iterator<const char*, Traits>;
+ static_assert(std::is_constructible<path, It>::value, "");
+ }
+ {
+ using It = output_iterator<const char*>;
+ static_assert(!std::is_constructible<path, It>::value, "");
+
+ }
+ {
+ static_assert(!std::is_constructible<path, int*>::value, "");
+ }
+}
+
+int main(int, char**) {
+ for (auto const& MS : PathList) {
+ RunTestCase<char>(MS);
+ RunTestCase<wchar_t>(MS);
+ RunTestCase<char16_t>(MS);
+ RunTestCase<char32_t>(MS);
+ }
+ test_sfinae();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/empty.fail.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/empty.fail.cpp
new file mode 100644
index 00000000000..5248f67515a
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/empty.fail.cpp
@@ -0,0 +1,29 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <filesystem>
+
+// class path
+
+// bool empty() const noexcept;
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
+// 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(int, char**)
+{
+ fs::path c;
+ c.empty(); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/path.decompose.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/path.decompose.pass.cpp
new file mode 100644
index 00000000000..be9cefb76a8
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.decompose/path.decompose.pass.cpp
@@ -0,0 +1,217 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// 8.4.9 path decomposition [path.decompose]
+//------------------------------------------
+// path root_name() const;
+// path root_directory() const;
+// path root_path() const;
+// path relative_path() const;
+// path parent_path() const;
+// path filename() const;
+// path stem() const;
+// path extension() const;
+//-------------------------------
+// 8.4.10 path query [path.query]
+//-------------------------------
+// bool empty() const noexcept;
+// bool has_root_path() const;
+// bool has_root_name() const;
+// bool has_root_directory() const;
+// bool has_relative_path() const;
+// bool has_parent_path() const;
+// bool has_filename() const;
+// bool has_stem() const;
+// bool has_extension() const;
+// bool is_absolute() const;
+// bool is_relative() const;
+//-------------------------------
+// 8.5 path iterators [path.itr]
+//-------------------------------
+// iterator begin() const;
+// iterator end() const;
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <vector>
+#include <cassert>
+
+#include "test_macros.h"
+#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
+{
+ std::string raw;
+ std::vector<std::string> elements;
+ std::string root_path;
+ std::string root_name;
+ std::string root_directory;
+ std::string relative_path;
+ std::string parent_path;
+ std::string filename;
+};
+
+const PathDecomposeTestcase PathTestCases[] =
+ {
+ {"", {}, "", "", "", "", "", ""}
+ , {".", {"."}, "", "", "", ".", "", "."}
+ , {"..", {".."}, "", "", "", "..", "", ".."}
+ , {"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/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/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar", "foo/.", "bar"}
+ , {"foo/../", {"foo", "..", ""}, "", "", "", "foo/../", "foo/..", ""}
+ , {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar", "foo/..", "bar"}
+ , {"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/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\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar", "c:", "foo\\bar"}
+ , {"//", {"/"}, "/", "", "/", "", "/", ""}
+ };
+
+void decompPathTest()
+{
+ using namespace fs;
+ for (auto const & TC : PathTestCases) {
+ CHECKPOINT(TC.raw.c_str());
+ fs::path p(TC.raw);
+ ASSERT(p == TC.raw);
+
+ ASSERT_EQ(p.root_path(), TC.root_path);
+ ASSERT_NEQ(p.has_root_path(), TC.root_path.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_EQ(p.root_directory(), TC.root_directory);
+ ASSERT_NEQ(p.has_root_directory(), TC.root_directory.empty());
+
+ ASSERT_EQ(p.relative_path(), TC.relative_path);
+ ASSERT_NEQ(p.has_relative_path(), TC.relative_path.empty());
+
+ ASSERT_EQ(p.parent_path(), TC.parent_path);
+ ASSERT_NEQ(p.has_parent_path(), TC.parent_path.empty());
+
+ ASSERT_EQ(p.filename(), TC.filename);
+ ASSERT_NEQ(p.has_filename(), TC.filename.empty());
+
+ 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_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_COLLECTION_EQ_COMP(Parts.begin(), Parts.end(),
+ TC.elements.rbegin(), TC.elements.rend(),
+ ComparePathExact());
+ }
+}
+
+
+struct FilenameDecompTestcase
+{
+ std::string raw;
+ std::string filename;
+ std::string stem;
+ std::string extension;
+};
+
+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"}
+};
+
+
+void decompFilenameTest()
+{
+ using namespace fs;
+ for (auto const & TC : FilenameTestCases) {
+ CHECKPOINT(TC.raw.c_str());
+ fs::path p(TC.raw);
+ ASSERT_EQ(p, TC.raw);
+ ASSERT_NOEXCEPT(p.empty());
+
+ ASSERT_EQ(p.filename(), TC.filename);
+ ASSERT_NEQ(p.has_filename(), TC.filename.empty());
+
+ ASSERT_EQ(p.stem(), TC.stem);
+ ASSERT_NEQ(p.has_stem(), TC.stem.empty());
+
+ ASSERT_EQ(p.extension(), TC.extension);
+ ASSERT_NEQ(p.has_extension(), TC.extension.empty());
+ }
+}
+
+int main(int, char**)
+{
+ decompPathTest();
+ decompFilenameTest();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_normal.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_normal.pass.cpp
new file mode 100644
index 00000000000..f1e616542e9
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_normal.pass.cpp
@@ -0,0 +1,141 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <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(int, char**) {
+ // 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/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp
new file mode 100644
index 00000000000..7e31956ee50
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <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(int, char**) {
+ // 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/input.output/filesystems/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp
new file mode 100644
index 00000000000..707a7010ffb
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class ECharT, class Traits = char_traits<ECharT>,
+// class Allocator = allocator<ECharT>>
+// basic_string<ECharT, Traits, Allocator>
+// generic_string(const Allocator& a = Allocator()) const;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+
+// generic_string<C, T, A> forwards to string<C, T, A>. Tests for
+// string<C, T, A>() are in "path.native.op/string_alloc.pass.cpp".
+// generic_string is minimally tested here.
+int main(int, char**)
+{
+ using namespace fs;
+ using CharT = wchar_t;
+ using Traits = std::char_traits<CharT>;
+ using Alloc = malloc_allocator<CharT>;
+ using Str = std::basic_string<CharT, Traits, Alloc>;
+ const wchar_t* expect = longString;
+ const path p((const char*)longString);
+ {
+ DisableAllocationGuard g;
+ Alloc a;
+ Alloc::disable_default_constructor = true;
+ Str s = p.generic_string<wchar_t, Traits, Alloc>(a);
+ assert(s == expect);
+ assert(Alloc::alloc_count > 0);
+ assert(Alloc::outstanding_alloc() == 1);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
new file mode 100644
index 00000000000..04ae673ac48
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// std::string generic_string() const;
+// std::wstring generic_wstring() const;
+// std::u8string generic_u8string() const;
+// std::u16string generic_u16string() const;
+// std::u32string generic_u32string() const;
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+int main(int, char**)
+{
+ using namespace fs;
+ auto const& MS = longString;
+ const char* value = longString;
+ const path p(value);
+ {
+ std::string s = p.generic_string();
+ assert(s == value);
+ }
+ {
+ std::string s = p.generic_u8string();
+ assert(s == (const char*)MS);
+ }
+ {
+ std::wstring s = p.generic_wstring();
+ assert(s == (const wchar_t*)MS);
+ }
+ {
+ std::u16string s = p.generic_u16string();
+ assert(s == (const char16_t*)MS);
+ }
+ {
+ std::u32string s = p.generic_u32string();
+ assert(s == (const char32_t*)MS);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/clear.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/clear.pass.cpp
new file mode 100644
index 00000000000..01538539faf
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/clear.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// void clear() noexcept
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+
+int main(int, char**) {
+ using namespace fs;
+ {
+ path p;
+ ASSERT_NOEXCEPT(p.clear());
+ ASSERT_SAME_TYPE(void, decltype(p.clear()));
+ p.clear();
+ assert(p.empty());
+ }
+ {
+ const path p("/foo/bar/baz");
+ path p2(p);
+ assert(p == p2);
+ p2.clear();
+ assert(p2.empty());
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/make_preferred.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/make_preferred.pass.cpp
new file mode 100644
index 00000000000..4530ef87554
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/make_preferred.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& make_preferred()
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+
+struct MakePreferredTestcase {
+ const char* value;
+};
+
+const MakePreferredTestcase TestCases[] =
+ {
+ {""}
+ , {"hello_world"}
+ , {"/"}
+ , {"/foo/bar/baz/"}
+ , {"\\"}
+ , {"\\foo\\bar\\baz\\"}
+ , {"\\foo\\/bar\\/baz\\"}
+ };
+
+int main(int, char**)
+{
+ // This operation is an identity operation on linux.
+ using namespace fs;
+ for (auto const & TC : TestCases) {
+ path p(TC.value);
+ assert(p == TC.value);
+ path& Ref = (p.make_preferred());
+ assert(p.native() == TC.value);
+ assert(&Ref == &p);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/remove_filename.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/remove_filename.pass.cpp
new file mode 100644
index 00000000000..7cb562c227f
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/remove_filename.pass.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& remove_filename()
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+#include "verbose_assert.h"
+
+struct RemoveFilenameTestcase {
+ const char* value;
+ const char* expect;
+};
+
+const RemoveFilenameTestcase TestCases[] =
+ {
+ {"", ""}
+ , {"/", "/"}
+ , {"//", "//"}
+ , {"///", "///"}
+ , {"\\", ""}
+ , {".", ""}
+ , {"..", ""}
+ , {"/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", "///"}
+ , {"file.txt", ""}
+ , {"bar/../baz/./file.txt", "bar/../baz/./"}
+ };
+
+int main(int, char**)
+{
+ using namespace fs;
+ for (auto const & TC : TestCases) {
+ path const p_orig(TC.value);
+ path p(p_orig);
+ assert(p == TC.value);
+ path& Ref = (p.remove_filename());
+ ASSERT_EQ(p, TC.expect) << DISPLAY(p_orig);
+ assert(&Ref == &p);
+ assert(!p.has_filename());
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_extension.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_extension.pass.cpp
new file mode 100644
index 00000000000..6fec420baa0
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_extension.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& replace_extension(path const& p = path())
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+
+struct ReplaceExtensionTestcase {
+ const char* value;
+ const char* expect;
+ const char* extension;
+};
+
+const ReplaceExtensionTestcase TestCases[] =
+ {
+ {"", "", ""}
+ , {"foo.cpp", "foo", ""}
+ , {"foo.cpp", "foo.", "."}
+ , {"foo..cpp", "foo..txt", "txt"}
+ , {"", ".txt", "txt"}
+ , {"", ".txt", ".txt"}
+ , {"/foo", "/foo.txt", ".txt"}
+ , {"/foo", "/foo.txt", "txt"}
+ , {"/foo.cpp", "/foo.txt", ".txt"}
+ , {"/foo.cpp", "/foo.txt", "txt"}
+ };
+const ReplaceExtensionTestcase NoArgCases[] =
+ {
+ {"", "", ""}
+ , {"foo", "foo", ""}
+ , {"foo.cpp", "foo", ""}
+ , {"foo..cpp", "foo.", ""}
+};
+
+int main(int, char**)
+{
+ using namespace fs;
+ for (auto const & TC : TestCases) {
+ path p(TC.value);
+ assert(p == TC.value);
+ path& Ref = (p.replace_extension(TC.extension));
+ assert(p == TC.expect);
+ assert(&Ref == &p);
+ }
+ for (auto const& TC : NoArgCases) {
+ path p(TC.value);
+ assert(p == TC.value);
+ path& Ref = (p.replace_extension());
+ assert(p == TC.expect);
+ assert(&Ref == &p);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_filename.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_filename.pass.cpp
new file mode 100644
index 00000000000..8142e790731
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/replace_filename.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// path& replace_filename()
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#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;
+ const char* expect;
+ const char* filename;
+};
+
+const ReplaceFilenameTestcase TestCases[] =
+ {
+ {"/foo", "/bar", "bar"}
+ , {"/foo", "/", ""}
+ , {"foo", "bar", "bar"}
+ , {"/", "/bar", "bar"}
+ , {"\\", "bar", "bar"}
+ , {"///", "///bar", "bar"}
+ , {"\\\\", "bar", "bar"}
+ , {"\\/\\", "\\/bar", "bar"}
+ , {".", "bar", "bar"}
+ , {"..", "bar", "bar"}
+ , {"/foo\\baz/bong/", "/foo\\baz/bong/bar", "bar"}
+ , {"/foo\\baz/bong", "/foo\\baz/bar", "bar"}
+ };
+
+int main(int, char**)
+{
+ using namespace fs;
+ for (auto const & TC : TestCases) {
+ path p(TC.value);
+ ASSERT_EQ(p, TC.value);
+ path& Ref = (p.replace_filename(TC.filename));
+ ASSERT_EQ(p, TC.expect)
+ << DISPLAY(TC.value)
+ << DISPLAY(TC.filename);
+ assert(&Ref == &p);
+ // Tests Effects "as-if": remove_filename() append(filename)
+ {
+ path p2(TC.value);
+ path replace(TC.filename);
+ p2.remove_filename();
+ p2 /= replace;
+ ASSERT_EQ(p, p2);
+ }
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/swap.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/swap.pass.cpp
new file mode 100644
index 00000000000..2e9dac5e438
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.modifiers/swap.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// void swap(path& rhs) noexcept;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+
+struct SwapTestcase {
+ const char* value1;
+ const char* value2;
+};
+
+#define LONG_STR1 "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG"
+#define LONG_STR2 "_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2"
+const SwapTestcase TestCases[] =
+ {
+ {"", ""}
+ , {"shortstr", LONG_STR1}
+ , {LONG_STR1, "shortstr"}
+ , {LONG_STR1, LONG_STR2}
+ };
+#undef LONG_STR1
+#undef LONG_STR2
+
+int main(int, char**)
+{
+ using namespace fs;
+ {
+ path p;
+ ASSERT_NOEXCEPT(p.swap(p));
+ ASSERT_SAME_TYPE(void, decltype(p.swap(p)));
+ }
+ for (auto const & TC : TestCases) {
+ path p1(TC.value1);
+ path p2(TC.value2);
+ {
+ DisableAllocationGuard g;
+ p1.swap(p2);
+ }
+ assert(p1 == TC.value2);
+ assert(p2 == TC.value1);
+ {
+ DisableAllocationGuard g;
+ p1.swap(p2);
+ }
+ assert(p1 == TC.value1);
+ assert(p2 == TC.value2);
+ }
+ // self-swap
+ {
+ const char* Val = "aoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeu";
+ path p1(Val);
+ assert(p1 == Val);
+ {
+ DisableAllocationGuard g;
+ p1.swap(p1);
+ }
+ assert(p1 == Val);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/c_str.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/c_str.pass.cpp
new file mode 100644
index 00000000000..8b35ee8c80a
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/c_str.pass.cpp
@@ -0,0 +1,43 @@
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// const value_type* c_str() const noexcept;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+
+int main(int, char**)
+{
+ using namespace fs;
+ const char* const value = "hello world";
+ const std::string str_value = value;
+ { // Check signature
+ path p(value);
+ ASSERT_SAME_TYPE(path::value_type const*, decltype(p.c_str()));
+ ASSERT_NOEXCEPT(p.c_str());
+ }
+ {
+ path p(value);
+ assert(p.c_str() == str_value);
+ assert(p.native().c_str() == p.c_str());
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp
new file mode 100644
index 00000000000..c06de9795e3
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// std::string string() const;
+// std::wstring wstring() const;
+// std::u8string u8string() const;
+// std::u16string u16string() const;
+// std::u32string u32string() const;
+
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+int main(int, char**)
+{
+ using namespace fs;
+ auto const& MS = longString;
+ const char* value = longString;
+ const path p(value);
+ {
+ std::string s = p.string();
+ assert(s == value);
+ }
+ {
+ std::string s = p.u8string();
+ assert(s == (const char*)MS);
+ }
+ {
+ std::wstring s = p.wstring();
+ assert(s == (const wchar_t*)MS);
+ }
+ {
+ std::u16string s = p.u16string();
+ assert(s == (const char16_t*)MS);
+ }
+ {
+ std::u32string s = p.u32string();
+ assert(s == (const char32_t*)MS);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/native.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/native.pass.cpp
new file mode 100644
index 00000000000..3b88b5d6c64
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/native.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// const string_type& native() const noexcept;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+
+int main(int, char**)
+{
+ using namespace fs;
+ const char* const value = "hello world";
+ { // Check signature
+ path p(value);
+ ASSERT_SAME_TYPE(path::string_type const&, decltype(p.native()));
+ ASSERT_NOEXCEPT(p.native());
+ }
+ { // native() is tested elsewhere
+ path p(value);
+ assert(p.native() == value);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/operator_string.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/operator_string.pass.cpp
new file mode 100644
index 00000000000..9f0069051fd
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/operator_string.pass.cpp
@@ -0,0 +1,47 @@
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// operator string_type() const;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+
+int main(int, char**)
+{
+ using namespace fs;
+ using string_type = path::string_type;
+ const char* const value = "hello world";
+ { // Check signature
+ path p(value);
+ static_assert(std::is_convertible<path, string_type>::value, "");
+ static_assert(std::is_constructible<string_type, path>::value, "");
+ ASSERT_SAME_TYPE(string_type, decltype(p.operator string_type()));
+ ASSERT_NOT_NOEXCEPT(p.operator string_type());
+ }
+ {
+ path p(value);
+ assert(p.native() == value);
+ string_type s = p;
+ assert(s == value);
+ assert(p == value);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/string_alloc.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/string_alloc.pass.cpp
new file mode 100644
index 00000000000..4ace380b873
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/string_alloc.pass.cpp
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class ECharT, class Traits = char_traits<ECharT>,
+// class Allocator = allocator<ECharT>>
+// basic_string<ECharT, Traits, Allocator>
+// string(const Allocator& a = Allocator()) const;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+
+// the SSO is always triggered for strings of size 2.
+MultiStringType shortString = MKSTR("a");
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+template <class CharT>
+void doShortStringTest(MultiStringType const& MS) {
+ using namespace fs;
+ using Ptr = CharT const*;
+ using Str = std::basic_string<CharT>;
+ using Alloc = std::allocator<CharT>;
+ Ptr value = MS;
+ const path p((const char*)MS);
+ {
+ DisableAllocationGuard g;
+ Str s = p.string<CharT>();
+ assert(s == value);
+ Str s2 = p.string<CharT>(Alloc{});
+ assert(s2 == value);
+ }
+ using MAlloc = malloc_allocator<CharT>;
+ MAlloc::reset();
+ {
+ using Traits = std::char_traits<CharT>;
+ using AStr = std::basic_string<CharT, Traits, MAlloc>;
+ DisableAllocationGuard g;
+ AStr s = p.string<CharT, Traits, MAlloc>();
+ assert(s == value);
+ assert(MAlloc::alloc_count == 0);
+ assert(MAlloc::outstanding_alloc() == 0);
+ }
+ MAlloc::reset();
+ { // Other allocator - provided copy
+ using Traits = std::char_traits<CharT>;
+ using AStr = std::basic_string<CharT, Traits, MAlloc>;
+ DisableAllocationGuard g;
+ MAlloc a;
+ // don't allow another allocator to be default constructed.
+ MAlloc::disable_default_constructor = true;
+ AStr s = p.string<CharT, Traits, MAlloc>(a);
+ assert(s == value);
+ assert(MAlloc::alloc_count == 0);
+ assert(MAlloc::outstanding_alloc() == 0);
+ }
+ MAlloc::reset();
+}
+
+template <class CharT>
+void doLongStringTest(MultiStringType const& MS) {
+ using namespace fs;
+ using Ptr = CharT const*;
+ using Str = std::basic_string<CharT>;
+ Ptr value = MS;
+ const path p((const char*)MS);
+ { // Default allocator
+ using Alloc = std::allocator<CharT>;
+ Str s = p.string<CharT>();
+ assert(s == value);
+ Str s2 = p.string<CharT>(Alloc{});
+ assert(s2 == value);
+ }
+ using MAlloc = malloc_allocator<CharT>;
+ MAlloc::reset();
+ { // Other allocator - default construct
+ using Traits = std::char_traits<CharT>;
+ using AStr = std::basic_string<CharT, Traits, MAlloc>;
+ DisableAllocationGuard g;
+ AStr s = p.string<CharT, Traits, MAlloc>();
+ assert(s == value);
+ assert(MAlloc::alloc_count > 0);
+ assert(MAlloc::outstanding_alloc() == 1);
+ }
+ MAlloc::reset();
+ { // Other allocator - provided copy
+ using Traits = std::char_traits<CharT>;
+ using AStr = std::basic_string<CharT, Traits, MAlloc>;
+ DisableAllocationGuard g;
+ MAlloc a;
+ // don't allow another allocator to be default constructed.
+ MAlloc::disable_default_constructor = true;
+ AStr s = p.string<CharT, Traits, MAlloc>(a);
+ assert(s == value);
+ assert(MAlloc::alloc_count > 0);
+ assert(MAlloc::outstanding_alloc() == 1);
+ }
+ MAlloc::reset();
+ /////////////////////////////////////////////////////////////////////////////
+}
+
+int main(int, char**)
+{
+ using namespace fs;
+ {
+ auto const& S = shortString;
+ doShortStringTest<char>(S);
+ doShortStringTest<wchar_t>(S);
+ doShortStringTest<char16_t>(S);
+ doShortStringTest<char32_t>(S);
+ }
+ {
+ auto const& S = longString;
+ doLongStringTest<char>(S);
+ doLongStringTest<wchar_t>(S);
+ doLongStringTest<char16_t>(S);
+ doLongStringTest<char32_t>(S);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp
new file mode 100644
index 00000000000..32c37e7f7a5
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+//-------------------------------
+// 8.4.10 path query [path.query]
+//-------------------------------
+// bool empty() const noexcept;
+// bool has_root_path() const;
+// bool has_root_name() const;
+// bool has_root_directory() const;
+// bool has_relative_path() const;
+// bool has_parent_path() const;
+// bool has_filename() const;
+// bool has_stem() const;
+// bool has_extension() const;
+// bool is_absolute() const;
+// bool is_relative() const;
+
+// tested in path.decompose
+int main(int, char**) {
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.fail.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.fail.cpp
new file mode 100644
index 00000000000..bcc4758f45f
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.fail.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+#include "filesystem_include.hpp"
+
+using namespace fs;
+
+struct ConvToPath {
+ operator fs::path() const {
+ return "";
+ }
+};
+
+int main(int, char**) {
+ ConvToPath LHS, RHS;
+ (void)(LHS / RHS); // expected-error {{invalid operands to binary expression}}
+
+ return 0;
+} \ No newline at end of file
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.pass.cpp
new file mode 100644
index 00000000000..67af37686df
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/append_op.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// path operator/(path const&, path const&);
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+// This is mainly tested via the member append functions.
+int main(int, char**)
+{
+ using namespace fs;
+ path p1("abc");
+ path p2("def");
+ path p3 = p1 / p2;
+ assert(p3 == "abc/def");
+
+ path p4 = p1 / "def";
+ assert(p4 == "abc/def");
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops.fail.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops.fail.cpp
new file mode 100644
index 00000000000..8f1732186d8
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops.fail.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+
+#include "filesystem_include.hpp"
+
+using namespace fs;
+
+struct ConvToPath {
+ operator fs::path() const {
+ return "";
+ }
+};
+
+int main(int, char**) {
+ ConvToPath LHS, RHS;
+ (void)(LHS == RHS); // expected-error {{invalid operands to binary expression}}
+ (void)(LHS != RHS); // expected-error {{invalid operands to binary expression}}
+ (void)(LHS < RHS); // expected-error {{invalid operands to binary expression}}
+ (void)(LHS <= RHS); // expected-error {{invalid operands to binary expression}}
+ (void)(LHS > RHS); // expected-error {{invalid operands to binary expression}}
+ (void)(LHS >= RHS); // expected-error {{invalid operands to binary expression}}
+
+ return 0;
+} \ No newline at end of file
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp
new file mode 100644
index 00000000000..c61a5a0254c
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// The comparison operators are tested as part of [path.compare]
+// in class.path/path.members/path.compare.pass.cpp
+int main(int, char**) {
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp
new file mode 100644
index 00000000000..49d28daf98f
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// The "hash_value" function is tested as part of [path.compare]
+// in class.path/path.members/path.compare.pass.cpp
+int main(int, char**) {
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp
new file mode 100644
index 00000000000..557849ca8e6
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// template <class Source>
+// path u8path(Source const&);
+// template <class InputIter>
+// path u8path(InputIter, InputIter);
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+
+int main(int, char**)
+{
+ using namespace fs;
+ const char* In1 = "abcd/efg";
+ const std::string In2(In1);
+ const auto In3 = In2.begin();
+ const auto In3End = In2.end();
+ {
+ path p = fs::u8path(In1);
+ assert(p == In1);
+ }
+ {
+ path p = fs::u8path(In2);
+ assert(p == In1);
+ }
+ {
+ path p = fs::u8path(In3);
+ assert(p == In1);
+ }
+ {
+ path p = fs::u8path(In3, In3End);
+ assert(p == In1);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.pass.cpp
new file mode 100644
index 00000000000..31eea925a5d
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const path& p);
+//
+// template <class charT, class traits>
+// basic_istream<charT, traits>&
+// operator>>(basic_istream<charT, traits>& is, path& p)
+//
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <sstream>
+#include <cassert>
+#include <iostream>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
+MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
+
+
+
+template <class CharT>
+void doIOTest() {
+ using namespace fs;
+ using Ptr = const CharT*;
+ using StrStream = std::basic_stringstream<CharT>;
+ const Ptr E = OutStr;
+ const path p((const char*)InStr);
+ StrStream ss;
+ { // test output
+ auto& ret = (ss << p);
+ assert(ss.str() == E);
+ assert(&ret == &ss);
+ }
+ { // test input
+ path p_in;
+ auto& ret = ss >> p_in;
+ assert(p_in.native() == (const char*)InStr);
+ assert(&ret == &ss);
+ }
+}
+
+namespace impl {
+using namespace fs;
+
+template <class Stream, class Tp, class = decltype(std::declval<Stream&>() << std::declval<Tp&>())>
+std::true_type is_ostreamable_imp(int);
+
+template <class Stream, class Tp>
+std::false_type is_ostreamable_imp(long);
+
+template <class Stream, class Tp, class = decltype(std::declval<Stream&>() >> std::declval<Tp&>())>
+std::true_type is_istreamable_imp(int);
+
+template <class Stream, class Tp>
+std::false_type is_istreamable_imp(long);
+
+
+} // namespace impl
+
+template <class Stream, class Tp>
+struct is_ostreamable : decltype(impl::is_ostreamable_imp<Stream, Tp>(0)) {};
+template <class Stream, class Tp>
+struct is_istreamable : decltype(impl::is_istreamable_imp<Stream, Tp>(0)) {};
+
+void test_LWG2989() {
+ static_assert(!is_ostreamable<decltype(std::cout), std::wstring>::value, "");
+ static_assert(!is_ostreamable<decltype(std::wcout), std::string>::value, "");
+ static_assert(!is_istreamable<decltype(std::cin), std::wstring>::value, "");
+ static_assert(!is_istreamable<decltype(std::wcin), std::string>::value, "");
+}
+
+int main(int, char**) {
+ doIOTest<char>();
+ doIOTest<wchar_t>();
+ //doIOTest<char16_t>();
+ //doIOTest<char32_t>();
+ test_LWG2989();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.unicode_bug.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.unicode_bug.pass.cpp
new file mode 100644
index 00000000000..c5bb6bf120f
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.io.unicode_bug.pass.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const path& p);
+//
+// template <class charT, class traits>
+// basic_istream<charT, traits>&
+// operator>>(basic_istream<charT, traits>& is, path& p)
+//
+
+// TODO(EricWF) This test fails because "std::quoted" fails to compile
+// for char16_t and char32_t types. Combine with path.io.pass.cpp when this
+// passes.
+// XFAIL: *
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <sstream>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
+MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
+
+template <class CharT>
+void doIOTest() {
+ using namespace fs;
+ using Ptr = const CharT*;
+ using StrStream = std::basic_stringstream<CharT>;
+ const char* const InCStr = InStr;
+ const Ptr E = OutStr;
+ const path p((const char*)InStr);
+ StrStream ss;
+ { // test output
+ auto& ret = (ss << p);
+ assert(ss.str() == E);
+ assert(&ret == &ss);
+ }
+ { // test input
+ path p_in;
+ auto& ret = ss >> p_in;
+ assert(p_in.native() == (const char*)InStr);
+ assert(&ret == &ss);
+ }
+}
+
+
+int main(int, char**) {
+ doIOTest<char16_t>();
+ doIOTest<char32_t>();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/swap.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/swap.pass.cpp
new file mode 100644
index 00000000000..51bb03e9f7c
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/swap.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// void swap(path& lhs, path& rhs) noexcept;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+
+// NOTE: this is tested in path.members/path.modifiers via the member swap.
+int main(int, char**)
+{
+ using namespace fs;
+ const char* value1 = "foo/bar/baz";
+ const char* value2 = "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG";
+ path p1(value1);
+ path p2(value2);
+ {
+ using namespace std; using namespace fs;
+ ASSERT_NOEXCEPT(swap(p1, p2));
+ ASSERT_SAME_TYPE(void, decltype(swap(p1, p2)));
+ }
+ {
+ DisableAllocationGuard g;
+ using namespace std;
+ using namespace fs;
+ swap(p1, p2);
+ assert(p1.native() == value2);
+ assert(p2.native() == value1);
+ swap(p1, p2);
+ assert(p1.native() == value1);
+ assert(p2.native() == value2);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/synop.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/synop.pass.cpp
new file mode 100644
index 00000000000..8aa186e32ae
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/synop.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// typedef ... value_type;
+// typedef basic_string<value_type> string_type;
+// static constexpr value_type preferred_separator = ...;
+
+#include "filesystem_include.hpp"
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+
+int main(int, char**) {
+ using namespace fs;
+ ASSERT_SAME_TYPE(path::value_type, char);
+ ASSERT_SAME_TYPE(path::string_type, std::basic_string<path::value_type>);
+ {
+ ASSERT_SAME_TYPE(const path::value_type, decltype(path::preferred_separator));
+ static_assert(path::preferred_separator == '/', "");
+ // Make preferred_separator ODR used by taking its address.
+ const char* dummy = &path::preferred_separator;
+ ((void)dummy);
+ }
+
+ return 0;
+}
OpenPOWER on IntegriCloud