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
9*ac8c9f1eSLouis Dionne // UNSUPPORTED: c++03, c++11, c++14
10c352fa74SLouis 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
27*ac8c9f1eSLouis Dionne #include <filesystem>
28f7b43230SLouis Dionne #include <type_traits>
29f7b43230SLouis Dionne #include <string_view>
30f7b43230SLouis Dionne #include <cassert>
31f7b43230SLouis Dionne
32f5f3a598SMartin Storsjö // On Windows, the append function converts all inputs (pointers, iterators)
33f5f3a598SMartin Storsjö // to an intermediate path object, causing allocations in cases where no
34f5f3a598SMartin Storsjö // allocations are done on other platforms.
35f5f3a598SMartin Storsjö
36c352fa74SLouis Dionne #include "../path_helper.h"
37cc89063bSNico Weber #include "count_new.h"
38c352fa74SLouis Dionne #include "make_string.h"
39c352fa74SLouis Dionne #include "test_iterators.h"
40c352fa74SLouis Dionne #include "test_macros.h"
41*ac8c9f1eSLouis Dionne namespace fs = std::filesystem;
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ö
expected_resultAppendOperatorTestcase4953d7c636SMartin 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>
doAppendSourceAllocTest(AppendOperatorTestcase const & TC)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>
doAppendSourceTest(AppendOperatorTestcase const & TC)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>()))>
has_append(int)325f7b43230SLouis Dionne constexpr bool has_append(int) { return true; }
326f7b43230SLouis Dionne template <class It>
has_append(long)327f7b43230SLouis Dionne constexpr bool has_append(long) { return false; }
328f7b43230SLouis Dionne
329f7b43230SLouis Dionne template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))>
has_append_op(int)330f7b43230SLouis Dionne constexpr bool has_append_op(int) { return true; }
331f7b43230SLouis Dionne template <class It>
has_append_op(long)332f7b43230SLouis Dionne constexpr bool has_append_op(long) { return false; }
333f7b43230SLouis Dionne
334f7b43230SLouis Dionne template <class It>
has_append()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
test_sfinae()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
main(int,char **)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