blob: 11bc5dd9b86e5a2d23c6096f5961c84602d8d712 [file] [log] [blame]
Eric Fiselier6e9a6942016-06-17 19:46:40 +00001//===----------------------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// UNSUPPORTED: c++98, c++03
11
12// <experimental/filesystem>
13
14// class path
15
16// path& operator/=(path const&)
17// template <class Source>
18// path& operator/=(Source const&);
19// template <class Source>
20// path& append(Source const&);
21// template <class InputIterator>
22// path& append(InputIterator first, InputIterator last);
23
24
Eric Fiselierf1471a32018-03-26 05:46:57 +000025#include "filesystem_include.hpp"
Eric Fiselier6e9a6942016-06-17 19:46:40 +000026#include <type_traits>
Eric Fiselier2645dbe2016-07-23 03:10:56 +000027#include <string_view>
Eric Fiselier6e9a6942016-06-17 19:46:40 +000028#include <cassert>
29
30#include "test_macros.h"
31#include "test_iterators.h"
32#include "count_new.hpp"
33#include "filesystem_test_helper.hpp"
Eric Fiselier1e34c762018-04-02 23:03:41 +000034#include "verbose_assert.h"
Eric Fiselier6e9a6942016-06-17 19:46:40 +000035
Eric Fiselier6e9a6942016-06-17 19:46:40 +000036
37struct AppendOperatorTestcase {
38 MultiStringType lhs;
39 MultiStringType rhs;
40 MultiStringType expect;
41};
42
43#define S(Str) MKSTR(Str)
44const AppendOperatorTestcase Cases[] =
45 {
46 {S(""), S(""), S("")}
47 , {S("p1"), S("p2"), S("p1/p2")}
48 , {S("p1/"), S("p2"), S("p1/p2")}
Eric Fiselier1e34c762018-04-02 23:03:41 +000049 , {S("p1"), S("/p2"), S("/p2")}
50 , {S("p1/"), S("/p2"), S("/p2")}
Eric Fiselier6e9a6942016-06-17 19:46:40 +000051 , {S("p1"), S("\\p2"), S("p1/\\p2")}
52 , {S("p1\\"), S("p2"), S("p1\\/p2")}
53 , {S("p1\\"), S("\\p2"), S("p1\\/\\p2")}
Eric Fiselier6e9a6942016-06-17 19:46:40 +000054 , {S(""), S("p2"), S("p2")}
Eric Fiselier1e34c762018-04-02 23:03:41 +000055 , {S("/p1"), S("p2"), S("/p1/p2")}
56 , {S("/p1"), S("/p2"), S("/p2")}
57 , {S("/p1/p3"), S("p2"), S("/p1/p3/p2")}
58 , {S("/p1/p3/"), S("p2"), S("/p1/p3/p2")}
59 , {S("/p1/"), S("p2"), S("/p1/p2")}
60 , {S("/p1/p3/"), S("/p2/p4"), S("/p2/p4")}
61 , {S("/"), S(""), S("/")}
62 , {S("/p1"), S("/p2/"), S("/p2/")}
63 , {S("p1"), S(""), S("p1/")}
64 , {S("p1/"), S(""), S("p1/")}
Eric Fiselier6e9a6942016-06-17 19:46:40 +000065 };
66
67
68const AppendOperatorTestcase LongLHSCases[] =
69 {
70 {S("p1"), S("p2"), S("p1/p2")}
71 , {S("p1/"), S("p2"), S("p1/p2")}
Eric Fiselier1e34c762018-04-02 23:03:41 +000072 , {S("p1"), S("/p2"), S("/p2")}
73 , {S("/p1"), S("p2"), S("/p1/p2")}
Eric Fiselier6e9a6942016-06-17 19:46:40 +000074 };
75#undef S
76
77
78// The append operator may need to allocate a temporary buffer before a code_cvt
79// conversion. Test if this allocation occurs by:
80// 1. Create a path, `LHS`, and reserve enough space to append `RHS`.
81// This prevents `LHS` from allocating during the actual appending.
82// 2. Create a `Source` object `RHS`, which represents a "large" string.
83// (The string must not trigger the SSO)
84// 3. Append `RHS` to `LHS` and check for the expected allocation behavior.
85template <class CharT>
86void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
87{
88 using namespace fs;
89 using Ptr = CharT const*;
90 using Str = std::basic_string<CharT>;
Eric Fiselier2645dbe2016-07-23 03:10:56 +000091 using StrView = std::basic_string_view<CharT>;
Eric Fiselier6e9a6942016-06-17 19:46:40 +000092 using InputIter = input_iterator<Ptr>;
93
94 const Ptr L = TC.lhs;
95 Str RShort = (Ptr)TC.rhs;
96 Str EShort = (Ptr)TC.expect;
97 assert(RShort.size() >= 2);
98 CharT c = RShort.back();
99 RShort.append(100, c);
100 EShort.append(100, c);
101 const Ptr R = RShort.data();
102 const Str& E = EShort;
103 std::size_t ReserveSize = E.size() + 3;
104 // basic_string
105 {
106 path LHS(L); PathReserve(LHS, ReserveSize);
107 Str RHS(R);
108 {
109 DisableAllocationGuard g;
110 LHS /= RHS;
111 }
Eric Fiselier1e34c762018-04-02 23:03:41 +0000112 ASSERT_PRED(PathEq, LHS , E);
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000113 }
Eric Fiselier2645dbe2016-07-23 03:10:56 +0000114 // basic_string_view
115 {
116 path LHS(L); PathReserve(LHS, ReserveSize);
117 StrView RHS(R);
118 {
119 DisableAllocationGuard g;
120 LHS /= RHS;
121 }
Eric Fiselier1e34c762018-04-02 23:03:41 +0000122 assert(PathEq(LHS, E));
Eric Fiselier2645dbe2016-07-23 03:10:56 +0000123 }
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000124 // CharT*
125 {
126 path LHS(L); PathReserve(LHS, ReserveSize);
127 Ptr RHS(R);
128 {
129 DisableAllocationGuard g;
130 LHS /= RHS;
131 }
Eric Fiselier1e34c762018-04-02 23:03:41 +0000132 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000133 }
134 {
135 path LHS(L); PathReserve(LHS, ReserveSize);
136 Ptr RHS(R);
137 {
138 DisableAllocationGuard g;
139 LHS.append(RHS, StrEnd(RHS));
140 }
Eric Fiselier1e34c762018-04-02 23:03:41 +0000141 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000142 }
143 // input iterator - For non-native char types, appends needs to copy the
Stephan T. Lavavej16e2ba12017-01-18 20:10:25 +0000144 // iterator range into a contiguous block of memory before it can perform the
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000145 // code_cvt conversions.
146 // For "char" no allocations will be performed because no conversion is
147 // required.
148 bool DisableAllocations = std::is_same<CharT, char>::value;
149 {
150 path LHS(L); PathReserve(LHS, ReserveSize);
151 InputIter RHS(R);
152 {
153 RequireAllocationGuard g; // requires 1 or more allocations occur by default
154 if (DisableAllocations) g.requireExactly(0);
155 LHS /= RHS;
156 }
Eric Fiselier1e34c762018-04-02 23:03:41 +0000157 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000158 }
159 {
160 path LHS(L); PathReserve(LHS, ReserveSize);
161 InputIter RHS(R);
162 InputIter REnd(StrEnd(R));
163 {
164 RequireAllocationGuard g;
165 if (DisableAllocations) g.requireExactly(0);
166 LHS.append(RHS, REnd);
167 }
Eric Fiselier1e34c762018-04-02 23:03:41 +0000168 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000169 }
170}
171
172template <class CharT>
173void doAppendSourceTest(AppendOperatorTestcase const& TC)
174{
175 using namespace fs;
176 using Ptr = CharT const*;
177 using Str = std::basic_string<CharT>;
Eric Fiselier2645dbe2016-07-23 03:10:56 +0000178 using StrView = std::basic_string_view<CharT>;
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000179 using InputIter = input_iterator<Ptr>;
180 const Ptr L = TC.lhs;
181 const Ptr R = TC.rhs;
182 const Ptr E = TC.expect;
183 // basic_string
184 {
Eric Fiselier1e34c762018-04-02 23:03:41 +0000185 path Result(L);
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000186 Str RHS(R);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000187 path& Ref = (Result /= RHS);
188 ASSERT_EQ(Result, E)
189 << DISPLAY(L) << DISPLAY(R);
190 assert(&Ref == &Result);
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000191 }
192 {
193 path LHS(L);
194 Str RHS(R);
195 path& Ref = LHS.append(RHS);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000196 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000197 assert(&Ref == &LHS);
198 }
Eric Fiselier2645dbe2016-07-23 03:10:56 +0000199 // basic_string_view
200 {
201 path LHS(L);
202 StrView RHS(R);
203 path& Ref = (LHS /= RHS);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000204 assert(PathEq(LHS, E));
Eric Fiselier2645dbe2016-07-23 03:10:56 +0000205 assert(&Ref == &LHS);
206 }
207 {
208 path LHS(L);
209 StrView RHS(R);
210 path& Ref = LHS.append(RHS);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000211 assert(PathEq(LHS, E));
Eric Fiselier2645dbe2016-07-23 03:10:56 +0000212 assert(&Ref == &LHS);
213 }
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000214 // Char*
215 {
216 path LHS(L);
217 Str RHS(R);
218 path& Ref = (LHS /= RHS);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000219 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000220 assert(&Ref == &LHS);
221 }
222 {
223 path LHS(L);
224 Ptr RHS(R);
225 path& Ref = LHS.append(RHS);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000226 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000227 assert(&Ref == &LHS);
228 }
229 {
230 path LHS(L);
231 Ptr RHS(R);
232 path& Ref = LHS.append(RHS, StrEnd(RHS));
Eric Fiselier1e34c762018-04-02 23:03:41 +0000233 ASSERT_PRED(PathEq, LHS, E)
234 << DISPLAY(L) << DISPLAY(R);
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000235 assert(&Ref == &LHS);
236 }
237 // iterators
238 {
239 path LHS(L);
240 InputIter RHS(R);
241 path& Ref = (LHS /= RHS);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000242 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000243 assert(&Ref == &LHS);
244 }
245 {
246 path LHS(L); InputIter RHS(R);
247 path& Ref = LHS.append(RHS);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000248 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000249 assert(&Ref == &LHS);
250 }
251 {
252 path LHS(L);
253 InputIter RHS(R);
254 InputIter REnd(StrEnd(R));
255 path& Ref = LHS.append(RHS, REnd);
Eric Fiselier1e34c762018-04-02 23:03:41 +0000256 assert(PathEq(LHS, E));
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000257 assert(&Ref == &LHS);
258 }
259}
260
Eric Fiselier113315b2016-08-28 21:26:01 +0000261
262
263template <class It, class = decltype(fs::path{}.append(std::declval<It>()))>
264constexpr bool has_append(int) { return true; }
265template <class It>
266constexpr bool has_append(long) { return false; }
267
268template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))>
269constexpr bool has_append_op(int) { return true; }
270template <class It>
271constexpr bool has_append_op(long) { return false; }
272
273template <class It>
274constexpr bool has_append() {
275 static_assert(has_append<It>(0) == has_append_op<It>(0), "must be same");
276 return has_append<It>(0) && has_append_op<It>(0);
277}
278
279void test_sfinae()
280{
281 using namespace fs;
282 {
283 using It = const char* const;
284 static_assert(has_append<It>(), "");
285 }
286 {
287 using It = input_iterator<const char*>;
288 static_assert(has_append<It>(), "");
289 }
290 {
291 struct Traits {
292 using iterator_category = std::input_iterator_tag;
293 using value_type = const char;
294 using pointer = const char*;
295 using reference = const char&;
296 using difference_type = std::ptrdiff_t;
297 };
298 using It = input_iterator<const char*, Traits>;
299 static_assert(has_append<It>(), "");
300 }
301 {
302 using It = output_iterator<const char*>;
303 static_assert(!has_append<It>(), "");
304
305 }
306 {
307 static_assert(!has_append<int*>(), "");
308 }
309 {
310 static_assert(!has_append<char>(), "");
311 static_assert(!has_append<const char>(), "");
312 }
313}
314
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000315int main()
316{
317 using namespace fs;
318 for (auto const & TC : Cases) {
319 {
Eric Fiselier1e34c762018-04-02 23:03:41 +0000320 const char* LHS_In = TC.lhs;
321 const char* RHS_In = TC.rhs;
322 path LHS(LHS_In);
323 path RHS(RHS_In);
324 path& Res = (LHS /= RHS);
325 ASSERT_PRED(PathEq, Res, (const char*)TC.expect)
326 << DISPLAY(LHS_In) << DISPLAY(RHS_In);
327 assert(&Res == &LHS);
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000328 }
329 doAppendSourceTest<char> (TC);
330 doAppendSourceTest<wchar_t> (TC);
331 doAppendSourceTest<char16_t>(TC);
332 doAppendSourceTest<char32_t>(TC);
333 }
334 for (auto const & TC : LongLHSCases) {
335 doAppendSourceAllocTest<char>(TC);
336 doAppendSourceAllocTest<wchar_t>(TC);
337 }
Eric Fiselier113315b2016-08-28 21:26:01 +0000338 test_sfinae();
Eric Fiselier6e9a6942016-06-17 19:46:40 +0000339}