xref: /llvm-project/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/source.pass.cpp (revision fde04e61cb7393f0ca982d7fc905a17767d93e6e)
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