1f7b43230SLouis Dionne //===----------------------------------------------------------------------===// 2f7b43230SLouis Dionne // 3f7b43230SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f7b43230SLouis Dionne // See https://llvm.org/LICENSE.txt for license information. 5f7b43230SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f7b43230SLouis Dionne // 7f7b43230SLouis Dionne //===----------------------------------------------------------------------===// 8f7b43230SLouis Dionne 931cbe0f2SLouis Dionne // UNSUPPORTED: c++03 10*c352fa74SLouis Dionne // UNSUPPORTED: availability-filesystem-missing 11f7b43230SLouis Dionne 1288ffc727SLouis Dionne // These tests require locale for non-char paths 13a7f9895cSLouis Dionne // UNSUPPORTED: no-localization 1488ffc727SLouis Dionne 15f7b43230SLouis Dionne // <filesystem> 16f7b43230SLouis Dionne 17f7b43230SLouis Dionne // class path 18f7b43230SLouis Dionne 19f7b43230SLouis Dionne // path& operator/=(path const&) 20f7b43230SLouis Dionne // template <class Source> 21f7b43230SLouis Dionne // path& operator/=(Source const&); 22f7b43230SLouis Dionne // template <class Source> 23f7b43230SLouis Dionne // path& append(Source const&); 24f7b43230SLouis Dionne // template <class InputIterator> 25f7b43230SLouis Dionne // path& append(InputIterator first, InputIterator last); 26f7b43230SLouis Dionne 27f7b43230SLouis Dionne 28cc89063bSNico Weber #include "filesystem_include.h" 29f7b43230SLouis Dionne #include <type_traits> 30f7b43230SLouis Dionne #include <string_view> 31f7b43230SLouis Dionne #include <cassert> 32f7b43230SLouis Dionne 33f5f3a598SMartin Storsjö // On Windows, the append function converts all inputs (pointers, iterators) 34f5f3a598SMartin Storsjö // to an intermediate path object, causing allocations in cases where no 35f5f3a598SMartin Storsjö // allocations are done on other platforms. 36f5f3a598SMartin Storsjö 37*c352fa74SLouis Dionne #include "../path_helper.h" 38cc89063bSNico Weber #include "count_new.h" 39*c352fa74SLouis Dionne #include "make_string.h" 40*c352fa74SLouis Dionne #include "test_iterators.h" 41*c352fa74SLouis Dionne #include "test_macros.h" 42f7b43230SLouis Dionne 43f7b43230SLouis Dionne struct AppendOperatorTestcase { 44f7b43230SLouis Dionne MultiStringType lhs; 45f7b43230SLouis Dionne MultiStringType rhs; 4653d7c636SMartin Storsjö MultiStringType expect_posix; 4753d7c636SMartin Storsjö MultiStringType expect_windows; 4853d7c636SMartin Storsjö 4953d7c636SMartin Storsjö MultiStringType const& expected_result() const { 5053d7c636SMartin Storsjö #ifdef _WIN32 5153d7c636SMartin Storsjö return expect_windows; 5253d7c636SMartin Storsjö #else 5353d7c636SMartin Storsjö return expect_posix; 5453d7c636SMartin Storsjö #endif 5553d7c636SMartin Storsjö } 56f7b43230SLouis Dionne }; 57f7b43230SLouis Dionne 58f7b43230SLouis Dionne #define S(Str) MKSTR(Str) 59f7b43230SLouis Dionne const AppendOperatorTestcase Cases[] = 60f7b43230SLouis Dionne { 6153d7c636SMartin Storsjö {S(""), S(""), S(""), S("")} 6253d7c636SMartin Storsjö , {S("p1"), S("p2"), S("p1/p2"), S("p1\\p2")} 6353d7c636SMartin Storsjö , {S("p1/"), S("p2"), S("p1/p2"), S("p1/p2")} 6453d7c636SMartin Storsjö , {S("p1"), S("/p2"), S("/p2"), S("/p2")} 6553d7c636SMartin Storsjö , {S("p1/"), S("/p2"), S("/p2"), S("/p2")} 6653d7c636SMartin Storsjö , {S("p1"), S("\\p2"), S("p1/\\p2"), S("\\p2")} 6753d7c636SMartin Storsjö , {S("p1\\"), S("p2"), S("p1\\/p2"), S("p1\\p2")} 6853d7c636SMartin Storsjö , {S("p1\\"), S("\\p2"), S("p1\\/\\p2"), S("\\p2")} 6953d7c636SMartin Storsjö , {S(""), S("p2"), S("p2"), S("p2")} 7053d7c636SMartin Storsjö , {S("/p1"), S("p2"), S("/p1/p2"), S("/p1\\p2")} 7153d7c636SMartin Storsjö , {S("/p1"), S("/p2"), S("/p2"), S("/p2")} 7253d7c636SMartin Storsjö , {S("/p1/p3"), S("p2"), S("/p1/p3/p2"), S("/p1/p3\\p2")} 7353d7c636SMartin Storsjö , {S("/p1/p3/"), S("p2"), S("/p1/p3/p2"), S("/p1/p3/p2")} 7453d7c636SMartin Storsjö , {S("/p1/"), S("p2"), S("/p1/p2"), S("/p1/p2")} 7553d7c636SMartin Storsjö , {S("/p1/p3/"), S("/p2/p4"), S("/p2/p4"), S("/p2/p4")} 7653d7c636SMartin Storsjö , {S("/"), S(""), S("/"), S("/")} 7753d7c636SMartin Storsjö , {S("/p1"), S("/p2/"), S("/p2/"), S("/p2/")} 7853d7c636SMartin Storsjö , {S("p1"), S(""), S("p1/"), S("p1\\")} 7953d7c636SMartin Storsjö , {S("p1/"), S(""), S("p1/"), S("p1/")} 8078d693faSMartin Storsjö 8153d7c636SMartin Storsjö , {S("//host"), S("foo"), S("//host/foo"), S("//host\\foo")} 8253d7c636SMartin Storsjö , {S("//host/"), S("foo"), S("//host/foo"), S("//host/foo")} 8353d7c636SMartin Storsjö , {S("//host"), S(""), S("//host/"), S("//host\\")} 8478d693faSMartin Storsjö 8553d7c636SMartin Storsjö , {S("foo"), S("C:/bar"), S("foo/C:/bar"), S("C:/bar")} 8653d7c636SMartin Storsjö , {S("foo"), S("C:"), S("foo/C:"), S("C:")} 8778d693faSMartin Storsjö 8853d7c636SMartin Storsjö , {S("C:"), S(""), S("C:/"), S("C:")} 8953d7c636SMartin Storsjö , {S("C:foo"), S("/bar"), S("/bar"), S("C:/bar")} 9053d7c636SMartin Storsjö , {S("C:foo"), S("bar"), S("C:foo/bar"), S("C:foo\\bar")} 9153d7c636SMartin Storsjö , {S("C:/foo"), S("bar"), S("C:/foo/bar"), S("C:/foo\\bar")} 9253d7c636SMartin Storsjö , {S("C:/foo"), S("/bar"), S("/bar"), S("C:/bar")} 9378d693faSMartin Storsjö 9453d7c636SMartin Storsjö , {S("C:foo"), S("C:/bar"), S("C:foo/C:/bar"), S("C:/bar")} 9553d7c636SMartin Storsjö , {S("C:foo"), S("C:bar"), S("C:foo/C:bar"), S("C:foo\\bar")} 9653d7c636SMartin Storsjö , {S("C:/foo"), S("C:/bar"), S("C:/foo/C:/bar"), S("C:/bar")} 9753d7c636SMartin Storsjö , {S("C:/foo"), S("C:bar"), S("C:/foo/C:bar"), S("C:/foo\\bar")} 9878d693faSMartin Storsjö 9953d7c636SMartin Storsjö , {S("C:foo"), S("c:/bar"), S("C:foo/c:/bar"), S("c:/bar")} 10053d7c636SMartin Storsjö , {S("C:foo"), S("c:bar"), S("C:foo/c:bar"), S("c:bar")} 10153d7c636SMartin Storsjö , {S("C:/foo"), S("c:/bar"), S("C:/foo/c:/bar"), S("c:/bar")} 10253d7c636SMartin Storsjö , {S("C:/foo"), S("c:bar"), S("C:/foo/c:bar"), S("c:bar")} 10378d693faSMartin Storsjö 10453d7c636SMartin Storsjö , {S("C:/foo"), S("D:bar"), S("C:/foo/D:bar"), S("D:bar")} 105f7b43230SLouis Dionne }; 106f7b43230SLouis Dionne 107f7b43230SLouis Dionne 108f7b43230SLouis Dionne const AppendOperatorTestcase LongLHSCases[] = 109f7b43230SLouis Dionne { 11053d7c636SMartin Storsjö {S("p1"), S("p2"), S("p1/p2"), S("p1\\p2")} 11153d7c636SMartin Storsjö , {S("p1/"), S("p2"), S("p1/p2"), S("p1/p2")} 11253d7c636SMartin Storsjö , {S("p1"), S("/p2"), S("/p2"), S("/p2")} 11353d7c636SMartin Storsjö , {S("/p1"), S("p2"), S("/p1/p2"), S("/p1\\p2")} 114f7b43230SLouis Dionne }; 115f7b43230SLouis Dionne #undef S 116f7b43230SLouis Dionne 117f7b43230SLouis Dionne 118f7b43230SLouis Dionne // The append operator may need to allocate a temporary buffer before a code_cvt 119f7b43230SLouis Dionne // conversion. Test if this allocation occurs by: 120f7b43230SLouis Dionne // 1. Create a path, `LHS`, and reserve enough space to append `RHS`. 121f7b43230SLouis Dionne // This prevents `LHS` from allocating during the actual appending. 122f7b43230SLouis Dionne // 2. Create a `Source` object `RHS`, which represents a "large" string. 123f7b43230SLouis Dionne // (The string must not trigger the SSO) 124f7b43230SLouis Dionne // 3. Append `RHS` to `LHS` and check for the expected allocation behavior. 125f7b43230SLouis Dionne template <class CharT> 126f7b43230SLouis Dionne void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) 127f7b43230SLouis Dionne { 128f7b43230SLouis Dionne using namespace fs; 129f7b43230SLouis Dionne using Ptr = CharT const*; 130f7b43230SLouis Dionne using Str = std::basic_string<CharT>; 131f7b43230SLouis Dionne using StrView = std::basic_string_view<CharT>; 132773ae441SChristopher Di Bella using InputIter = cpp17_input_iterator<Ptr>; 133f7b43230SLouis Dionne 134f7b43230SLouis Dionne const Ptr L = TC.lhs; 135f7b43230SLouis Dionne Str RShort = (Ptr)TC.rhs; 13653d7c636SMartin Storsjö Str EShort = (Ptr)TC.expected_result(); 137f7b43230SLouis Dionne assert(RShort.size() >= 2); 138f7b43230SLouis Dionne CharT c = RShort.back(); 139f7b43230SLouis Dionne RShort.append(100, c); 140f7b43230SLouis Dionne EShort.append(100, c); 141f7b43230SLouis Dionne const Ptr R = RShort.data(); 142f7b43230SLouis Dionne const Str& E = EShort; 143f7b43230SLouis Dionne std::size_t ReserveSize = E.size() + 3; 144f7b43230SLouis Dionne // basic_string 145f7b43230SLouis Dionne { 146f7b43230SLouis Dionne path LHS(L); PathReserve(LHS, ReserveSize); 147f7b43230SLouis Dionne Str RHS(R); 148f7b43230SLouis Dionne { 149f5f3a598SMartin Storsjö TEST_NOT_WIN32(DisableAllocationGuard g); 150f7b43230SLouis Dionne LHS /= RHS; 151f7b43230SLouis Dionne } 152e557b6a6SLouis Dionne assert(PathEq(LHS, E)); 153f7b43230SLouis Dionne } 154f7b43230SLouis Dionne // basic_string_view 155f7b43230SLouis Dionne { 156f7b43230SLouis Dionne path LHS(L); PathReserve(LHS, ReserveSize); 157f7b43230SLouis Dionne StrView RHS(R); 158f7b43230SLouis Dionne { 159f5f3a598SMartin Storsjö TEST_NOT_WIN32(DisableAllocationGuard g); 160f7b43230SLouis Dionne LHS /= RHS; 161f7b43230SLouis Dionne } 162f7b43230SLouis Dionne assert(PathEq(LHS, E)); 163f7b43230SLouis Dionne } 164f7b43230SLouis Dionne // CharT* 165f7b43230SLouis Dionne { 166f7b43230SLouis Dionne path LHS(L); PathReserve(LHS, ReserveSize); 167f7b43230SLouis Dionne Ptr RHS(R); 168f7b43230SLouis Dionne { 169f5f3a598SMartin Storsjö TEST_NOT_WIN32(DisableAllocationGuard g); 170f7b43230SLouis Dionne LHS /= RHS; 171f7b43230SLouis Dionne } 172f7b43230SLouis Dionne assert(PathEq(LHS, E)); 173f7b43230SLouis Dionne } 174f7b43230SLouis Dionne { 175f7b43230SLouis Dionne path LHS(L); PathReserve(LHS, ReserveSize); 176f7b43230SLouis Dionne Ptr RHS(R); 177f7b43230SLouis Dionne { 178f5f3a598SMartin Storsjö TEST_NOT_WIN32(DisableAllocationGuard g); 179f7b43230SLouis Dionne LHS.append(RHS, StrEnd(RHS)); 180f7b43230SLouis Dionne } 181f7b43230SLouis Dionne assert(PathEq(LHS, E)); 182f7b43230SLouis Dionne } 18349173ca4SMartin Storsjö { 18449173ca4SMartin Storsjö path LHS(L); PathReserve(LHS, ReserveSize); 18549173ca4SMartin Storsjö path RHS(R); 18649173ca4SMartin Storsjö { 18749173ca4SMartin Storsjö DisableAllocationGuard g; 18849173ca4SMartin Storsjö LHS /= RHS; 18949173ca4SMartin Storsjö } 19049173ca4SMartin Storsjö assert(PathEq(LHS, E)); 19149173ca4SMartin Storsjö } 192f7b43230SLouis Dionne // input iterator - For non-native char types, appends needs to copy the 193f7b43230SLouis Dionne // iterator range into a contiguous block of memory before it can perform the 194f7b43230SLouis Dionne // code_cvt conversions. 195f7b43230SLouis Dionne // For "char" no allocations will be performed because no conversion is 196f7b43230SLouis Dionne // required. 197f5f3a598SMartin Storsjö // On Windows, the append method is more complex and uses intermediate 198128b2136SMartin Storsjö // path objects, which causes extra allocations. This is checked by comparing 199128b2136SMartin Storsjö // path::value_type with "char" - on Windows, it's wchar_t. 200128b2136SMartin Storsjö #if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS 201128b2136SMartin Storsjö // Only check allocations if we can pick up allocations done within the 202128b2136SMartin Storsjö // library implementation. 203128b2136SMartin Storsjö bool ExpectNoAllocations = std::is_same<CharT, char>::value && 204128b2136SMartin Storsjö std::is_same<path::value_type, char>::value; 205f5f3a598SMartin Storsjö #endif 206f7b43230SLouis Dionne { 207f7b43230SLouis Dionne path LHS(L); PathReserve(LHS, ReserveSize); 208f7b43230SLouis Dionne InputIter RHS(R); 209f7b43230SLouis Dionne { 210128b2136SMartin Storsjö RequireAllocationGuard g(0); // require "at least zero" allocations by default 211128b2136SMartin Storsjö #if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS 212128b2136SMartin Storsjö if (ExpectNoAllocations) 213128b2136SMartin Storsjö g.requireExactly(0); 214128b2136SMartin Storsjö #endif 215f7b43230SLouis Dionne LHS /= RHS; 216f7b43230SLouis Dionne } 217f7b43230SLouis Dionne assert(PathEq(LHS, E)); 218f7b43230SLouis Dionne } 219f7b43230SLouis Dionne { 220f7b43230SLouis Dionne path LHS(L); PathReserve(LHS, ReserveSize); 221f7b43230SLouis Dionne InputIter RHS(R); 222f7b43230SLouis Dionne InputIter REnd(StrEnd(R)); 223f7b43230SLouis Dionne { 224128b2136SMartin Storsjö RequireAllocationGuard g(0); // require "at least zero" allocations by default 225128b2136SMartin Storsjö #if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS 226128b2136SMartin Storsjö if (ExpectNoAllocations) 227128b2136SMartin Storsjö g.requireExactly(0); 228128b2136SMartin Storsjö #endif 229f7b43230SLouis Dionne LHS.append(RHS, REnd); 230f7b43230SLouis Dionne } 231f7b43230SLouis Dionne assert(PathEq(LHS, E)); 232f7b43230SLouis Dionne } 233f7b43230SLouis Dionne } 234f7b43230SLouis Dionne 235f7b43230SLouis Dionne template <class CharT> 236f7b43230SLouis Dionne void doAppendSourceTest(AppendOperatorTestcase const& TC) 237f7b43230SLouis Dionne { 238f7b43230SLouis Dionne using namespace fs; 239f7b43230SLouis Dionne using Ptr = CharT const*; 240f7b43230SLouis Dionne using Str = std::basic_string<CharT>; 241f7b43230SLouis Dionne using StrView = std::basic_string_view<CharT>; 242773ae441SChristopher Di Bella using InputIter = cpp17_input_iterator<Ptr>; 243f7b43230SLouis Dionne const Ptr L = TC.lhs; 244f7b43230SLouis Dionne const Ptr R = TC.rhs; 24553d7c636SMartin Storsjö const Ptr E = TC.expected_result(); 246f7b43230SLouis Dionne // basic_string 247f7b43230SLouis Dionne { 248f7b43230SLouis Dionne path Result(L); 249f7b43230SLouis Dionne Str RHS(R); 250f7b43230SLouis Dionne path& Ref = (Result /= RHS); 251e557b6a6SLouis Dionne assert(Result == E); 252f7b43230SLouis Dionne assert(&Ref == &Result); 253f7b43230SLouis Dionne } 254f7b43230SLouis Dionne { 255f7b43230SLouis Dionne path LHS(L); 256f7b43230SLouis Dionne Str RHS(R); 257f7b43230SLouis Dionne path& Ref = LHS.append(RHS); 258f7b43230SLouis Dionne assert(PathEq(LHS, E)); 259f7b43230SLouis Dionne assert(&Ref == &LHS); 260f7b43230SLouis Dionne } 261f7b43230SLouis Dionne // basic_string_view 262f7b43230SLouis Dionne { 263f7b43230SLouis Dionne path LHS(L); 264f7b43230SLouis Dionne StrView RHS(R); 265f7b43230SLouis Dionne path& Ref = (LHS /= RHS); 266f7b43230SLouis Dionne assert(PathEq(LHS, E)); 267f7b43230SLouis Dionne assert(&Ref == &LHS); 268f7b43230SLouis Dionne } 269f7b43230SLouis Dionne { 270f7b43230SLouis Dionne path LHS(L); 271f7b43230SLouis Dionne StrView RHS(R); 272f7b43230SLouis Dionne path& Ref = LHS.append(RHS); 273f7b43230SLouis Dionne assert(PathEq(LHS, E)); 274f7b43230SLouis Dionne assert(&Ref == &LHS); 275f7b43230SLouis Dionne } 276f7b43230SLouis Dionne // Char* 277f7b43230SLouis Dionne { 278f7b43230SLouis Dionne path LHS(L); 279f7b43230SLouis Dionne Str RHS(R); 280f7b43230SLouis Dionne path& Ref = (LHS /= RHS); 281f7b43230SLouis Dionne assert(PathEq(LHS, E)); 282f7b43230SLouis Dionne assert(&Ref == &LHS); 283f7b43230SLouis Dionne } 284f7b43230SLouis Dionne { 285f7b43230SLouis Dionne path LHS(L); 286f7b43230SLouis Dionne Ptr RHS(R); 287f7b43230SLouis Dionne path& Ref = LHS.append(RHS); 288f7b43230SLouis Dionne assert(PathEq(LHS, E)); 289f7b43230SLouis Dionne assert(&Ref == &LHS); 290f7b43230SLouis Dionne } 291f7b43230SLouis Dionne { 292f7b43230SLouis Dionne path LHS(L); 293f7b43230SLouis Dionne Ptr RHS(R); 294f7b43230SLouis Dionne path& Ref = LHS.append(RHS, StrEnd(RHS)); 295e557b6a6SLouis Dionne assert(PathEq(LHS, E)); 296f7b43230SLouis Dionne assert(&Ref == &LHS); 297f7b43230SLouis Dionne } 298f7b43230SLouis Dionne // iterators 299f7b43230SLouis Dionne { 300f7b43230SLouis Dionne path LHS(L); 301f7b43230SLouis Dionne InputIter RHS(R); 302f7b43230SLouis Dionne path& Ref = (LHS /= RHS); 303f7b43230SLouis Dionne assert(PathEq(LHS, E)); 304f7b43230SLouis Dionne assert(&Ref == &LHS); 305f7b43230SLouis Dionne } 306f7b43230SLouis Dionne { 307f7b43230SLouis Dionne path LHS(L); InputIter RHS(R); 308f7b43230SLouis Dionne path& Ref = LHS.append(RHS); 309f7b43230SLouis Dionne assert(PathEq(LHS, E)); 310f7b43230SLouis Dionne assert(&Ref == &LHS); 311f7b43230SLouis Dionne } 312f7b43230SLouis Dionne { 313f7b43230SLouis Dionne path LHS(L); 314f7b43230SLouis Dionne InputIter RHS(R); 315f7b43230SLouis Dionne InputIter REnd(StrEnd(R)); 316f7b43230SLouis Dionne path& Ref = LHS.append(RHS, REnd); 317f7b43230SLouis Dionne assert(PathEq(LHS, E)); 318f7b43230SLouis Dionne assert(&Ref == &LHS); 319f7b43230SLouis Dionne } 320f7b43230SLouis Dionne } 321f7b43230SLouis Dionne 322f7b43230SLouis Dionne 323f7b43230SLouis Dionne 324f7b43230SLouis Dionne template <class It, class = decltype(fs::path{}.append(std::declval<It>()))> 325f7b43230SLouis Dionne constexpr bool has_append(int) { return true; } 326f7b43230SLouis Dionne template <class It> 327f7b43230SLouis Dionne constexpr bool has_append(long) { return false; } 328f7b43230SLouis Dionne 329f7b43230SLouis Dionne template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))> 330f7b43230SLouis Dionne constexpr bool has_append_op(int) { return true; } 331f7b43230SLouis Dionne template <class It> 332f7b43230SLouis Dionne constexpr bool has_append_op(long) { return false; } 333f7b43230SLouis Dionne 334f7b43230SLouis Dionne template <class It> 335f7b43230SLouis Dionne constexpr bool has_append() { 336f7b43230SLouis Dionne static_assert(has_append<It>(0) == has_append_op<It>(0), "must be same"); 337f7b43230SLouis Dionne return has_append<It>(0) && has_append_op<It>(0); 338f7b43230SLouis Dionne } 339f7b43230SLouis Dionne 340f7b43230SLouis Dionne void test_sfinae() 341f7b43230SLouis Dionne { 342f7b43230SLouis Dionne using namespace fs; 343f7b43230SLouis Dionne { 344f7b43230SLouis Dionne using It = const char* const; 345f7b43230SLouis Dionne static_assert(has_append<It>(), ""); 346f7b43230SLouis Dionne } 347f7b43230SLouis Dionne { 348773ae441SChristopher Di Bella using It = cpp17_input_iterator<const char*>; 349f7b43230SLouis Dionne static_assert(has_append<It>(), ""); 350f7b43230SLouis Dionne } 351f7b43230SLouis Dionne { 352f7b43230SLouis Dionne struct Traits { 353f7b43230SLouis Dionne using iterator_category = std::input_iterator_tag; 354f7b43230SLouis Dionne using value_type = const char; 355f7b43230SLouis Dionne using pointer = const char*; 356f7b43230SLouis Dionne using reference = const char&; 357f7b43230SLouis Dionne using difference_type = std::ptrdiff_t; 358f7b43230SLouis Dionne }; 359773ae441SChristopher Di Bella using It = cpp17_input_iterator<const char*, Traits>; 360f7b43230SLouis Dionne static_assert(has_append<It>(), ""); 361f7b43230SLouis Dionne } 362f7b43230SLouis Dionne { 3635e97d37bSMark de Wever using It = cpp17_output_iterator<const char*>; 364f7b43230SLouis Dionne static_assert(!has_append<It>(), ""); 365f7b43230SLouis Dionne 366f7b43230SLouis Dionne } 367f7b43230SLouis Dionne { 368f7b43230SLouis Dionne static_assert(!has_append<int*>(), ""); 369f7b43230SLouis Dionne } 370f7b43230SLouis Dionne { 371f7b43230SLouis Dionne static_assert(!has_append<char>(), ""); 372f7b43230SLouis Dionne static_assert(!has_append<const char>(), ""); 373f7b43230SLouis Dionne } 374f7b43230SLouis Dionne } 375f7b43230SLouis Dionne 376f7b43230SLouis Dionne int main(int, char**) 377f7b43230SLouis Dionne { 378f7b43230SLouis Dionne using namespace fs; 379f7b43230SLouis Dionne for (auto const & TC : Cases) { 380f7b43230SLouis Dionne { 381f7b43230SLouis Dionne const char* LHS_In = TC.lhs; 382f7b43230SLouis Dionne const char* RHS_In = TC.rhs; 383f7b43230SLouis Dionne path LHS(LHS_In); 384f7b43230SLouis Dionne path RHS(RHS_In); 385f7b43230SLouis Dionne path& Res = (LHS /= RHS); 38653d7c636SMartin Storsjö assert(PathEq(Res, (const char*)TC.expected_result())); 387f7b43230SLouis Dionne assert(&Res == &LHS); 388f7b43230SLouis Dionne } 389f7b43230SLouis Dionne doAppendSourceTest<char> (TC); 390f4c1258dSLouis Dionne #ifndef TEST_HAS_NO_WIDE_CHARACTERS 391f7b43230SLouis Dionne doAppendSourceTest<wchar_t> (TC); 392f4c1258dSLouis Dionne #endif 393f7b43230SLouis Dionne doAppendSourceTest<char16_t>(TC); 394f7b43230SLouis Dionne doAppendSourceTest<char32_t>(TC); 395f7b43230SLouis Dionne } 396f7b43230SLouis Dionne for (auto const & TC : LongLHSCases) { 39722e5ee0eSMartin Storsjö (void)TC; 398afe40b30SMartin Storsjö LIBCPP_ONLY(doAppendSourceAllocTest<char>(TC)); 399f4c1258dSLouis Dionne #ifndef TEST_HAS_NO_WIDE_CHARACTERS 400afe40b30SMartin Storsjö LIBCPP_ONLY(doAppendSourceAllocTest<wchar_t>(TC)); 401f4c1258dSLouis Dionne #endif 402f7b43230SLouis Dionne } 403f7b43230SLouis Dionne test_sfinae(); 404f7b43230SLouis Dionne 405f7b43230SLouis Dionne return 0; 406f7b43230SLouis Dionne } 407