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>
RunTestCase(MultiStringType const & MS)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(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, 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, 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, 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, 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, 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, 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>()))>
has_assign(int)179 constexpr bool has_assign(int) { return true; }
180 template <class It>
has_assign(long)181 constexpr bool has_assign(long) { return false; }
182 template <class It>
has_assign()183 constexpr bool has_assign() { return has_assign<It>(0); }
184
test_sfinae()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
RunStringMoveTest(const fs::path::value_type * Expect)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
main(int,char **)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