]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
Vendor import of libc++ trunk r351319 (just before the release_80
[FreeBSD/FreeBSD.git] / test / std / input.output / filesystems / class.path / path.member / path.concat.pass.cpp
1 //===----------------------------------------------------------------------===//
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 // <filesystem>
13
14 // class path
15
16 // path& operator+=(const path& x);
17 // path& operator+=(const string_type& x);
18 // path& operator+=(string_view x);
19 // path& operator+=(const value_type* x);
20 // path& operator+=(value_type x);
21 // template <class Source>
22 //   path& operator+=(const Source& x);
23 // template <class EcharT>
24 //   path& operator+=(EcharT x);
25 // template <class Source>
26 //   path& concat(const Source& x);
27 // template <class InputIterator>
28 //   path& concat(InputIterator first, InputIterator last);
29
30
31 #include "filesystem_include.hpp"
32 #include <type_traits>
33 #include <string>
34 #include <string_view>
35 #include <cassert>
36
37 #include "test_macros.h"
38 #include "test_iterators.h"
39 #include "count_new.hpp"
40 #include "filesystem_test_helper.hpp"
41
42
43 struct ConcatOperatorTestcase {
44   MultiStringType lhs;
45   MultiStringType rhs;
46   MultiStringType expect;
47 };
48
49 #define LONGSTR "LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR"
50 #define S(Str) MKSTR(Str)
51 const ConcatOperatorTestcase Cases[] =
52     {
53         {S(""),         S(""),                  S("")}
54       , {S("p1"),       S("p2"),                S("p1p2")}
55       , {S("p1/"),      S("/p2"),               S("p1//p2")}
56       , {S(""),         S("\\foo/bar/baz"),     S("\\foo/bar/baz")}
57       , {S("c:\\foo"),  S(""),                  S("c:\\foo")}
58       , {S(LONGSTR),    S("foo"),               S(LONGSTR "foo")}
59       , {S("abcdefghijklmnopqrstuvwxyz/\\"), S("/\\123456789"), S("abcdefghijklmnopqrstuvwxyz/\\/\\123456789")}
60     };
61 const ConcatOperatorTestcase LongLHSCases[] =
62     {
63         {S(""),        S(LONGSTR),     S(LONGSTR)}
64       , {S("p1/"),     S(LONGSTR),      S("p1/" LONGSTR)}
65     };
66 const ConcatOperatorTestcase CharTestCases[] =
67     {
68         {S(""),       S("P"), S("P")}
69       , {S("/fooba"), S("r"), S("/foobar")}
70     };
71 #undef S
72 #undef LONGSTR
73
74 // The concat operator may need to allocate a temporary buffer before a code_cvt
75 // conversion. Test if this allocation occurs by:
76 //   1. Create a path, `LHS`, and reserve enough space to append `RHS`.
77 //      This prevents `LHS` from allocating during the actual appending.
78 //   2. Create a `Source` object `RHS`, which represents a "large" string.
79 //      (The string must not trigger the SSO)
80 //   3. Concat `RHS` to `LHS` and check for the expected allocation behavior.
81 template <class CharT>
82 void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC)
83 {
84   using namespace fs;
85   using Ptr = CharT const*;
86   using Str = std::basic_string<CharT>;
87   using StrView = std::basic_string_view<CharT>;
88   using InputIter = input_iterator<Ptr>;
89
90   const Ptr L = TC.lhs;
91   const Ptr R = TC.rhs;
92   const Ptr E =  TC.expect;
93   std::size_t ReserveSize = StrLen(E) + 1;
94   // basic_string
95   {
96     path LHS(L); PathReserve(LHS, ReserveSize);
97     Str  RHS(R);
98     {
99       DisableAllocationGuard g;
100       LHS += RHS;
101     }
102     assert(LHS == E);
103   }
104   // basic_string_view
105   {
106     path LHS(L); PathReserve(LHS, ReserveSize);
107     StrView  RHS(R);
108     {
109       DisableAllocationGuard g;
110       LHS += RHS;
111     }
112     assert(LHS == E);
113   }
114   // CharT*
115   {
116     path LHS(L); PathReserve(LHS, ReserveSize);
117     Ptr RHS(R);
118     {
119       DisableAllocationGuard g;
120       LHS += RHS;
121     }
122     assert(LHS == E);
123   }
124   {
125     path LHS(L); PathReserve(LHS, ReserveSize);
126     Ptr RHS(R);
127     {
128       DisableAllocationGuard g;
129       LHS.concat(RHS, StrEnd(RHS));
130     }
131     assert(LHS == E);
132   }
133   // input iterator - For non-native char types, appends needs to copy the
134   // iterator range into a contiguous block of memory before it can perform the
135   // code_cvt conversions.
136   // For "char" no allocations will be performed because no conversion is
137   // required.
138   bool DisableAllocations = std::is_same<CharT, char>::value;
139   {
140     path LHS(L); PathReserve(LHS, ReserveSize);
141     InputIter RHS(R);
142     {
143       RequireAllocationGuard  g; // requires 1 or more allocations occur by default
144       if (DisableAllocations) g.requireExactly(0);
145       LHS += RHS;
146     }
147     assert(LHS == E);
148   }
149   {
150     path LHS(L); PathReserve(LHS, ReserveSize);
151     InputIter RHS(R);
152     InputIter REnd(StrEnd(R));
153     {
154       RequireAllocationGuard g;
155       if (DisableAllocations) g.requireExactly(0);
156       LHS.concat(RHS, REnd);
157     }
158     assert(LHS == E);
159   }
160 }
161
162 template <class CharT>
163 void doConcatSourceTest(ConcatOperatorTestcase const& TC)
164 {
165   using namespace fs;
166   using Ptr = CharT const*;
167   using Str = std::basic_string<CharT>;
168   using StrView = std::basic_string_view<CharT>;
169   using InputIter = input_iterator<Ptr>;
170   const Ptr L = TC.lhs;
171   const Ptr R = TC.rhs;
172   const Ptr E = TC.expect;
173   // basic_string
174   {
175     path LHS(L);
176     Str RHS(R);
177     path& Ref = (LHS += RHS);
178     assert(LHS == E);
179     assert(&Ref == &LHS);
180   }
181   {
182     path LHS(L);
183     Str RHS(R);
184     path& Ref = LHS.concat(RHS);
185     assert(LHS == E);
186     assert(&Ref == &LHS);
187   }
188   // basic_string_view
189   {
190     path LHS(L);
191     StrView RHS(R);
192     path& Ref = (LHS += RHS);
193     assert(LHS == E);
194     assert(&Ref == &LHS);
195   }
196   {
197     path LHS(L);
198     StrView RHS(R);
199     path& Ref = LHS.concat(RHS);
200     assert(LHS == E);
201     assert(&Ref == &LHS);
202   }
203   // Char*
204   {
205     path LHS(L);
206     Str RHS(R);
207     path& Ref = (LHS += RHS);
208     assert(LHS == E);
209     assert(&Ref == &LHS);
210   }
211   {
212     path LHS(L);
213     Ptr RHS(R);
214     path& Ref = LHS.concat(RHS);
215     assert(LHS == E);
216     assert(&Ref == &LHS);
217   }
218   {
219     path LHS(L);
220     Ptr RHS(R);
221     path& Ref = LHS.concat(RHS, StrEnd(RHS));
222     assert(LHS == E);
223     assert(&Ref == &LHS);
224   }
225   // iterators
226   {
227     path LHS(L);
228     InputIter RHS(R);
229     path& Ref = (LHS += RHS);
230     assert(LHS == E);
231     assert(&Ref == &LHS);
232   }
233   {
234     path LHS(L); InputIter RHS(R);
235     path& Ref = LHS.concat(RHS);
236     assert(LHS == E);
237     assert(&Ref == &LHS);
238   }
239   {
240     path LHS(L);
241     InputIter RHS(R);
242     InputIter REnd(StrEnd(R));
243     path& Ref = LHS.concat(RHS, REnd);
244     assert(LHS == E);
245     assert(&Ref == &LHS);
246   }
247 }
248
249 template <class CharT>
250 void doConcatECharTest(ConcatOperatorTestcase const& TC)
251 {
252   using namespace fs;
253   using Ptr = CharT const*;
254   const Ptr RStr = TC.rhs;
255   assert(StrLen(RStr) == 1);
256   const Ptr L   = TC.lhs;
257   const CharT R = RStr[0];
258   const Ptr E   = TC.expect;
259   {
260     path LHS(L);
261     path& Ref = (LHS += R);
262     assert(LHS == E);
263     assert(&Ref == &LHS);
264   }
265 }
266
267
268 template <class It, class = decltype(fs::path{}.concat(std::declval<It>()))>
269 constexpr bool has_concat(int) { return true; }
270 template <class It>
271 constexpr bool has_concat(long) { return false; }
272
273 template <class It, class = decltype(fs::path{}.operator+=(std::declval<It>()))>
274 constexpr bool has_concat_op(int) { return true; }
275 template <class It>
276 constexpr bool has_concat_op(long) { return false; }
277 template <class It>
278 constexpr bool has_concat_op() { return has_concat_op<It>(0); }
279
280 template <class It>
281 constexpr bool has_concat() {
282   static_assert(has_concat<It>(0) == has_concat_op<It>(0), "must be same");
283   return has_concat<It>(0) && has_concat_op<It>(0);
284 }
285
286 void test_sfinae() {
287   using namespace fs;
288   {
289     static_assert(has_concat_op<char>(), "");
290     static_assert(has_concat_op<const char>(), "");
291     static_assert(has_concat_op<char16_t>(), "");
292     static_assert(has_concat_op<const char16_t>(), "");
293   }
294   {
295     using It = const char* const;
296     static_assert(has_concat<It>(), "");
297   }
298   {
299     using It = input_iterator<const char*>;
300     static_assert(has_concat<It>(), "");
301   }
302   {
303     struct Traits {
304       using iterator_category = std::input_iterator_tag;
305       using value_type = const char;
306       using pointer = const char*;
307       using reference = const char&;
308       using difference_type = std::ptrdiff_t;
309     };
310     using It = input_iterator<const char*, Traits>;
311     static_assert(has_concat<It>(), "");
312   }
313   {
314     using It = output_iterator<const char*>;
315     static_assert(!has_concat<It>(), "");
316   }
317   {
318     static_assert(!has_concat<int>(0), "");
319     // operator+=(int) is well formed since it converts to operator+=(value_type)
320     // but concat(int) isn't valid because there is no concat(value_type).
321     // This should probably be addressed by a LWG issue.
322     static_assert(has_concat_op<int>(), "");
323   }
324   {
325     static_assert(!has_concat<int*>(), "");
326   }
327 }
328
329 int main()
330 {
331   using namespace fs;
332   for (auto const & TC : Cases) {
333     {
334       path LHS((const char*)TC.lhs);
335       path RHS((const char*)TC.rhs);
336       path& Ref = (LHS += RHS);
337       assert(LHS == (const char*)TC.expect);
338       assert(&Ref == &LHS);
339     }
340     {
341       path LHS((const char*)TC.lhs);
342       std::string_view RHS((const char*)TC.rhs);
343       path& Ref = (LHS += RHS);
344       assert(LHS == (const char*)TC.expect);
345       assert(&Ref == &LHS);
346     }
347     doConcatSourceTest<char>    (TC);
348     doConcatSourceTest<wchar_t> (TC);
349     doConcatSourceTest<char16_t>(TC);
350     doConcatSourceTest<char32_t>(TC);
351   }
352   for (auto const & TC : LongLHSCases) {
353     // Do path test
354     {
355       path LHS((const char*)TC.lhs);
356       path RHS((const char*)TC.rhs);
357       const char* E = TC.expect;
358       PathReserve(LHS, StrLen(E) + 5);
359       {
360         DisableAllocationGuard g;
361         path& Ref = (LHS += RHS);
362         assert(&Ref == &LHS);
363       }
364       assert(LHS == E);
365     }
366     {
367       path LHS((const char*)TC.lhs);
368       std::string_view RHS((const char*)TC.rhs);
369       const char* E = TC.expect;
370       PathReserve(LHS, StrLen(E) + 5);
371       {
372         DisableAllocationGuard g;
373         path& Ref = (LHS += RHS);
374         assert(&Ref == &LHS);
375       }
376       assert(LHS == E);
377     }
378     doConcatSourceAllocTest<char>(TC);
379     doConcatSourceAllocTest<wchar_t>(TC);
380   }
381   for (auto const& TC : CharTestCases) {
382     doConcatECharTest<char>(TC);
383     doConcatECharTest<wchar_t>(TC);
384     doConcatECharTest<char16_t>(TC);
385     doConcatECharTest<char32_t>(TC);
386   }
387   test_sfinae();
388 }