summaryrefslogtreecommitdiffstats
path: root/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp')
-rw-r--r--libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp389
1 files changed, 389 insertions, 0 deletions
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;
+}
OpenPOWER on IntegriCloud