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(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>()))> 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_ONLY(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