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