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: 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>
RunTestCase(MultiStringType const & MS)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 = cpp17_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 = cpp17_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 = cpp17_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>()))>
has_assign(int)178 constexpr bool has_assign(int) { return true; }
179 template <class It>
has_assign(long)180 constexpr bool has_assign(long) { return false; }
181 template <class It>
has_assign()182 constexpr bool has_assign() { return has_assign<It>(0); }
183
test_sfinae()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 = cpp17_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 = cpp17_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 = cpp17_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
RunStringMoveTest(const fs::path::value_type * Expect)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
main(int,char **)236 int main(int, char**) {
237 for (auto const& MS : PathList) {
238 RunTestCase<char>(MS);
239 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
240 RunTestCase<wchar_t>(MS);
241 #endif
242 RunTestCase<char16_t>(MS);
243 RunTestCase<char32_t>(MS);
244 RunStringMoveTest(MS);
245 }
246 test_sfinae();
247
248 return 0;
249 }
250