xref: /llvm-project/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/source.pass.cpp (revision c352fa7407122ee62d990d6b82551650149f98d4)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03
10 // UNSUPPORTED: availability-filesystem-missing
11 
12 // These tests require locale for non-char paths
13 // UNSUPPORTED: no-localization
14 
15 // <filesystem>
16 
17 // class path
18 
19 // template <class Source>
20 //      path& operator=(Source const&);
21 //  path& operator=(string_type&&);
22 // template <class Source>
23 //      path& assign(Source const&);
24 // template <class InputIterator>
25 //      path& assign(InputIterator first, InputIterator last);
26 
27 
28 #include "filesystem_include.h"
29 #include <type_traits>
30 #include <string_view>
31 #include <cassert>
32 
33 // On Windows, charset conversions cause allocations in the path class in
34 // cases where no allocations are done on other platforms.
35 
36 #include "../../path_helper.h"
37 #include "count_new.h"
38 #include "make_string.h"
39 #include "test_iterators.h"
40 #include "test_macros.h"
41 
42 
43 template <class CharT>
44 void RunTestCase(MultiStringType const& MS) {
45   using namespace fs;
46   const fs::path::value_type* Expect = MS;
47   const CharT* TestPath = MS;
48   const CharT* TestPathEnd = StrEnd(TestPath);
49   const std::size_t Size = TestPathEnd - TestPath;
50   const std::size_t SSize = StrEnd(Expect) - Expect;
51   assert(Size == SSize);
52   //////////////////////////////////////////////////////////////////////////////
53   // basic_string<Char, Traits, Alloc>
54   {
55     const std::basic_string<CharT> S(TestPath);
56     path p; PathReserve(p, S.length() + 1);
57     {
58       // string provides a contiguous iterator. No allocation needed.
59       TEST_NOT_WIN32(DisableAllocationGuard g);
60       path& pref = (p = S);
61       assert(&pref == &p);
62     }
63     assert(p.native() == Expect);
64     assert(p.string<CharT>() == TestPath);
65     assert(p.string<CharT>() == S);
66   }
67   {
68     const std::basic_string<CharT> S(TestPath);
69     path p; PathReserve(p, S.length() + 1);
70     {
71       TEST_NOT_WIN32(DisableAllocationGuard g);
72       path& pref = p.assign(S);
73       assert(&pref == &p);
74     }
75     assert(p.native() == Expect);
76     assert(p.string<CharT>() == TestPath);
77     assert(p.string<CharT>() == S);
78   }
79   // basic_string<Char, Traits, Alloc>
80   {
81     const std::basic_string_view<CharT> S(TestPath);
82     path p; PathReserve(p, S.length() + 1);
83     {
84       // string provides a contiguous iterator. No allocation needed.
85       TEST_NOT_WIN32(DisableAllocationGuard g);
86       path& pref = (p = S);
87       assert(&pref == &p);
88     }
89     assert(p.native() == Expect);
90     assert(p.string<CharT>() == TestPath);
91     assert(p.string<CharT>() == S);
92   }
93   {
94     const std::basic_string_view<CharT> S(TestPath);
95     path p; PathReserve(p, S.length() + 1);
96     {
97       TEST_NOT_WIN32(DisableAllocationGuard g);
98       path& pref = p.assign(S);
99       assert(&pref == &p);
100     }
101     assert(p.native() == Expect);
102     assert(p.string<CharT>() == TestPath);
103     assert(p.string<CharT>() == S);
104   }
105   //////////////////////////////////////////////////////////////////////////////
106   // Char* pointers
107   {
108     path p; PathReserve(p, Size + 1);
109     {
110       // char* pointers are contiguous and can be used with code_cvt directly.
111       // no allocations needed.
112       TEST_NOT_WIN32(DisableAllocationGuard g);
113       path& pref = (p = TestPath);
114       assert(&pref == &p);
115     }
116     assert(p.native() == Expect);
117     assert(p.string<CharT>() == TestPath);
118   }
119   {
120     path p; PathReserve(p, Size + 1);
121     {
122       TEST_NOT_WIN32(DisableAllocationGuard g);
123       path& pref = p.assign(TestPath);
124       assert(&pref == &p);
125     }
126     assert(p.native() == Expect);
127     assert(p.string<CharT>() == TestPath);
128   }
129   {
130     path p; PathReserve(p, Size + 1);
131     {
132       TEST_NOT_WIN32(DisableAllocationGuard g);
133       path& pref = p.assign(TestPath, TestPathEnd);
134       assert(&pref == &p);
135     }
136     assert(p.native() == Expect);
137     assert(p.string<CharT>() == TestPath);
138   }
139   //////////////////////////////////////////////////////////////////////////////
140   // Iterators
141   {
142     using It = cpp17_input_iterator<const CharT*>;
143     path p; PathReserve(p, Size + 1);
144     It it(TestPath);
145     {
146       // Iterators cannot be used with code_cvt directly. This assignment
147       // may allocate if it's larger than a "short-string".
148       path& pref = (p = it);
149       assert(&pref == &p);
150     }
151     assert(p.native() == Expect);
152     assert(p.string<CharT>() == TestPath);
153   }
154   {
155     using It = cpp17_input_iterator<const CharT*>;
156     path p; PathReserve(p, Size + 1);
157     It it(TestPath);
158     {
159       path& pref = p.assign(it);
160       assert(&pref == &p);
161     }
162     assert(p.native() == Expect);
163     assert(p.string<CharT>() == TestPath);
164   }
165   {
166     using It = cpp17_input_iterator<const CharT*>;
167     path p; PathReserve(p, Size + 1);
168     It it(TestPath);
169     It e(TestPathEnd);
170     {
171       path& pref = p.assign(it, e);
172       assert(&pref == &p);
173     }
174     assert(p.native() == Expect);
175     assert(p.string<CharT>() == TestPath);
176   }
177 }
178 
179 template <class It, class = decltype(fs::path{}.assign(std::declval<It>()))>
180 constexpr bool has_assign(int) { return true; }
181 template <class It>
182 constexpr bool has_assign(long) { return false; }
183 template <class It>
184 constexpr bool has_assign() { return has_assign<It>(0); }
185 
186 void test_sfinae() {
187   using namespace fs;
188   {
189     using It = const char* const;
190     static_assert(std::is_assignable<path, It>::value, "");
191     static_assert(has_assign<It>(), "");
192   }
193   {
194     using It = cpp17_input_iterator<const char*>;
195     static_assert(std::is_assignable<path, It>::value, "");
196     static_assert(has_assign<It>(), "");
197   }
198   {
199     struct Traits {
200       using iterator_category = std::input_iterator_tag;
201       using value_type = const char;
202       using pointer = const char*;
203       using reference = const char&;
204       using difference_type = std::ptrdiff_t;
205     };
206     using It = cpp17_input_iterator<const char*, Traits>;
207     static_assert(std::is_assignable<path, It>::value, "");
208     static_assert(has_assign<It>(), "");
209   }
210   {
211     using It = cpp17_output_iterator<const char*>;
212     static_assert(!std::is_assignable<path, It>::value, "");
213     static_assert(!has_assign<It>(), "");
214 
215   }
216   {
217     static_assert(!std::is_assignable<path, int*>::value, "");
218     static_assert(!has_assign<int*>(), "");
219   }
220 }
221 
222 void RunStringMoveTest(const fs::path::value_type* Expect) {
223   using namespace fs;
224   fs::path::string_type ss(Expect);
225   path p;
226   {
227     DisableAllocationGuard g; ((void)g);
228     path& pr = (p = std::move(ss));
229     assert(&pr == &p);
230   }
231   assert(p == Expect);
232   {
233     // Signature test
234     LIBCPP_ONLY(ASSERT_NOEXCEPT(p = std::move(ss)));
235   }
236 }
237 
238 int main(int, char**) {
239   for (auto const& MS : PathList) {
240     RunTestCase<char>(MS);
241 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
242     RunTestCase<wchar_t>(MS);
243 #endif
244     RunTestCase<char16_t>(MS);
245     RunTestCase<char32_t>(MS);
246     RunStringMoveTest(MS);
247   }
248   test_sfinae();
249 
250   return 0;
251 }
252