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