diff options
Diffstat (limited to 'test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp')
-rw-r--r-- | test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp new file mode 100644 index 0000000000000..a02ef18c453d6 --- /dev/null +++ b/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp @@ -0,0 +1,339 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// <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() +{ + 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(); +} |