1 //---------------------------------------------------------------------------------------
2 //
3 // Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 //
23 //---------------------------------------------------------------------------------------
24 #include <algorithm>
25 #include <cstdio>
26 #include <cstring>
27 #include <fstream>
28 #include <functional>
29 #include <iomanip>
30 #include <iostream>
31 #include <map>
32 #include <random>
33 #include <set>
34 #include <sstream>
35 #include <thread>
36 
37 #if (defined(WIN32) || defined(_WIN32)) && !defined(__GNUC__)
38 #define NOMINMAX 1
39 #endif
40 
41 #ifdef USE_STD_FS
42 #include <filesystem>
43 namespace fs {
44 using namespace std::filesystem;
45 using ifstream = std::ifstream;
46 using ofstream = std::ofstream;
47 using fstream = std::fstream;
48 }  // namespace fs
49 #ifdef __GNUC__
50 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
51 #endif
52 #ifdef _MSC_VER
53 #define IS_WCHAR_PATH
54 #endif
55 #ifdef WIN32
56 #define GHC_OS_WINDOWS
57 #endif
58 #else
59 #ifdef GHC_FILESYSTEM_FWD_TEST
60 #include <ghc/fs_fwd.hpp>
61 #else
62 #include <ghc/filesystem.hpp>
63 #endif
64 namespace fs {
65 using namespace ghc::filesystem;
66 using ifstream = ghc::filesystem::ifstream;
67 using ofstream = ghc::filesystem::ofstream;
68 using fstream = ghc::filesystem::fstream;
69 }  // namespace fs
70 #endif
71 
72 #if defined(WIN32) || defined(_WIN32)
73 #include <windows.h>
74 #else
75 #include <sys/socket.h>
76 #include <sys/stat.h>
77 #include <sys/types.h>
78 #include <sys/un.h>
79 #endif
80 
81 #ifndef GHC_FILESYSTEM_FWD_TEST
82 #define CATCH_CONFIG_MAIN
83 #endif
84 #include "catch.hpp"
85 
86 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
87 // Behaviour Switches (should match the config in ghc/filesystem.hpp):
88 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
89 // LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories
90 #define TEST_LWG_2682_BEHAVIOUR
91 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
92 // LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
93 // file with that name, it is superceded by P1164R1, so only activate if really needed
94 // #define TEST_LWG_2935_BEHAVIOUR
95 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
96 // LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
97 #define TEST_LWG_2937_BEHAVIOUR
98 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
99 
100 template <typename TP>
to_time_t(TP tp)101 std::time_t to_time_t(TP tp)
102 {
103     using namespace std::chrono;
104     auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now());
105     return system_clock::to_time_t(sctp);
106 }
107 
108 template <typename TP>
from_time_t(std::time_t t)109 TP from_time_t(std::time_t t)
110 {
111     using namespace std::chrono;
112     auto sctp = system_clock::from_time_t(t);
113     auto tp = time_point_cast<typename TP::duration>(sctp - system_clock::now() + TP::clock::now());
114     return tp;
115 }
116 
117 namespace Catch {
118 template <>
119 struct StringMaker<fs::path>
120 {
convertCatch::StringMaker121     static std::string convert(fs::path const& value) { return '"' + value.string() + '"'; }
122 };
123 
124 template <>
125 struct StringMaker<fs::perms>
126 {
convertCatch::StringMaker127     static std::string convert(fs::perms const& value) { return std::to_string(static_cast<unsigned int>(value)); }
128 };
129 
130 template <>
131 struct StringMaker<fs::file_time_type>
132 {
convertCatch::StringMaker133     static std::string convert(fs::file_time_type const& value)
134     {
135         std::time_t t = to_time_t(value);
136         std::tm* ptm = std::localtime(&t);
137         std::ostringstream os;
138         if (ptm) {
139             std::tm ttm = *ptm;
140             os << std::put_time(&ttm, "%Y-%m-%d %H:%M:%S");
141         }
142         else {
143             os << "(invalid-time)";
144         }
145         return os.str();
146     }
147 };
148 }  // namespace Catch
149 
150 enum class TempOpt { none, change_path };
151 class TemporaryDirectory
152 {
153 public:
TemporaryDirectory(TempOpt opt=TempOpt::none)154     TemporaryDirectory(TempOpt opt = TempOpt::none)
155     {
156         static auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
157         static auto rng = std::bind(std::uniform_int_distribution<int>(0, 35), std::mt19937(static_cast<unsigned int>(seed) ^ static_cast<unsigned int>(reinterpret_cast<ptrdiff_t>(&opt))));
158         std::string filename;
159         do {
160             filename = "test_";
161             for (int i = 0; i < 8; ++i) {
162                 filename += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[rng()];
163             }
164             _path = fs::canonical(fs::temp_directory_path()) / filename;
165         } while (fs::exists(_path));
166         fs::create_directories(_path);
167         if (opt == TempOpt::change_path) {
168             _orig_dir = fs::current_path();
169             fs::current_path(_path);
170         }
171     }
172 
~TemporaryDirectory()173     ~TemporaryDirectory()
174     {
175         if (!_orig_dir.empty()) {
176             fs::current_path(_orig_dir);
177         }
178         fs::remove_all(_path);
179     }
180 
path() const181     const fs::path& path() const { return _path; }
182 
183 private:
184     fs::path _path;
185     fs::path _orig_dir;
186 };
187 
generateFile(const fs::path & pathname,int withSize=-1)188 static void generateFile(const fs::path& pathname, int withSize = -1)
189 {
190     fs::ofstream outfile(pathname);
191     if (withSize < 0) {
192         outfile << "Hello world!" << std::endl;
193     }
194     else {
195         outfile << std::string(size_t(withSize), '*');
196     }
197 }
198 
199 #ifdef GHC_OS_WINDOWS
isWow64Proc()200 inline bool isWow64Proc()
201 {
202     typedef BOOL(WINAPI * IsWow64Process_t)(HANDLE, PBOOL);
203     BOOL bIsWow64 = FALSE;
204     auto fnIsWow64Process = (IsWow64Process_t)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
205     if (NULL != fnIsWow64Process) {
206         if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) {
207             bIsWow64 = FALSE;
208         }
209     }
210     return bIsWow64 == TRUE;
211 }
212 
is_symlink_creation_supported()213 static bool is_symlink_creation_supported()
214 {
215     bool result = true;
216     HKEY key;
217     REGSAM flags = KEY_READ;
218 #ifdef _WIN64
219     flags |= KEY_WOW64_64KEY;
220 #elif defined(KEY_WOW64_64KEY)
221     if (isWow64Proc()) {
222         flags |= KEY_WOW64_64KEY;
223     }
224     else {
225         flags |= KEY_WOW64_32KEY;
226     }
227 #else
228     result = false;
229 #endif
230     if (result) {
231         auto err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", 0, flags, &key);
232         if (err == ERROR_SUCCESS) {
233             DWORD val = 0, size = sizeof(DWORD);
234             err = RegQueryValueExW(key, L"AllowDevelopmentWithoutDevLicense", 0, NULL, reinterpret_cast<LPBYTE>(&val), &size);
235             RegCloseKey(key);
236             if (err != ERROR_SUCCESS) {
237                 result = false;
238             }
239             else {
240                 result = (val != 0);
241             }
242         }
243         else {
244             result = false;
245         }
246     }
247     if (!result) {
248         std::clog << "Warning: Symlink creation not supported." << std::endl;
249     }
250     return result;
251 }
252 #else
is_symlink_creation_supported()253 static bool is_symlink_creation_supported()
254 {
255     return true;
256 }
257 #endif
258 
has_host_root_name_support()259 static bool has_host_root_name_support()
260 {
261     return fs::path("//host").has_root_name();
262 }
263 
264 template <class T>
265 class TestAllocator
266 {
267 public:
268     using value_type = T;
269 
TestAllocator()270     TestAllocator() noexcept {}
271     template <class U>
TestAllocator(TestAllocator<U> const &)272     TestAllocator(TestAllocator<U> const&) noexcept
273     {
274     }
275 
allocate(std::size_t n)276     value_type* allocate(std::size_t n) { return static_cast<value_type*>(::operator new(n * sizeof(value_type))); }
277 
deallocate(value_type * p,std::size_t)278     void deallocate(value_type* p, std::size_t) noexcept { ::operator delete(p); }
279 };
280 
281 template <class T, class U>
operator ==(TestAllocator<T> const &,TestAllocator<U> const &)282 bool operator==(TestAllocator<T> const&, TestAllocator<U> const&) noexcept
283 {
284     return true;
285 }
286 
287 template <class T, class U>
operator !=(TestAllocator<T> const & x,TestAllocator<U> const & y)288 bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept
289 {
290     return !(x == y);
291 }
292 
293 TEST_CASE("Temporary Directory", "[fs.test.tempdir]")
294 {
295     fs::path tempPath;
296     {
297         TemporaryDirectory t;
298         tempPath = t.path();
299         REQUIRE(fs::exists(fs::path(t.path())));
300         REQUIRE(fs::is_directory(t.path()));
301     }
302     REQUIRE(!fs::exists(tempPath));
303 }
304 
305 #ifdef GHC_FILESYSTEM_VERSION
306 TEST_CASE("fs::detail::fromUtf8", "[filesystem][fs.detail.utf8]")
307 {
308     CHECK(fs::detail::fromUtf8<std::wstring>("foobar").length() == 6);
309     CHECK(fs::detail::fromUtf8<std::wstring>("foobar") == L"foobar");
310     CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar").length() == 6);
311     CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar") == L"föobar");
312 
313     CHECK(fs::detail::toUtf8(std::wstring(L"foobar")).length() == 6);
314     CHECK(fs::detail::toUtf8(std::wstring(L"foobar")) == "foobar");
315     CHECK(fs::detail::toUtf8(std::wstring(L"föobar")).length() == 7);
316     CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar");
317 
318 #ifdef GHC_RAISE_UNICODE_ERRORS
319     CHECK_THROWS_AS(fs::detail::fromUtf8<std::u16string>(std::string("\xed\xa0\x80")), fs::filesystem_error);
320     CHECK_THROWS_AS(fs::detail::fromUtf8<std::u16string>(std::string("\xc3")), fs::filesystem_error);
321 #else
322     CHECK(std::u16string(2,0xfffd) == fs::detail::fromUtf8<std::u16string>(std::string("\xed\xa0\x80")));
323     CHECK(std::u16string(1,0xfffd) == fs::detail::fromUtf8<std::u16string>(std::string("\xc3")));
324 #endif
325 }
326 
327 TEST_CASE("fs::detail::toUtf8", "[filesystem][fs.detail.utf8]")
328 {
329     std::string t;
330     CHECK(std::string("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e") == fs::detail::toUtf8(std::u16string(u"\u00E4/\u20AC\U0001D11E")));
331 #ifdef GHC_RAISE_UNICODE_ERRORS
332     CHECK_THROWS_AS(fs::detail::toUtf8(std::u16string(1, 0xd800)), fs::filesystem_error);
333     CHECK_THROWS_AS(fs::detail::appendUTF8(t, 0x200000), fs::filesystem_error);
334 #else
335     CHECK(std::string("\xEF\xBF\xBD") == fs::detail::toUtf8(std::u16string(1, 0xd800)));
336     fs::detail::appendUTF8(t, 0x200000);
337     CHECK(std::string("\xEF\xBF\xBD") == t);
338 #endif
339 }
340 #endif
341 
342 TEST_CASE("30.10.8.1 path::preferred_separator", "[filesystem][path][fs.path.generic]")
343 {
344 #ifdef GHC_OS_WINDOWS
345     CHECK(fs::path::preferred_separator == '\\');
346 #else
347     CHECK(fs::path::preferred_separator == '/');
348 #endif
349 }
350 
351 #ifndef GHC_OS_WINDOWS
352 TEST_CASE("30.10.8.1 path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]")
353 {
354     if (!has_host_root_name_support()) {
355         WARN("This implementation doesn't support path(\"//host\").has_root_name() == true [C++17 30.12.8.1 par. 4] on this platform, tests based on this are skipped. (Should be okay.)");
356     }
357 }
358 #endif
359 
360 TEST_CASE("30.10.8.4.1 path constructors and destructor", "[filesystem][path][fs.path.construct]")
361 {
362     CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
363     std::string str = "/usr/local/bin";
364     std::u16string u16str = u"/usr/local/bin";
365     std::u32string u32str = U"/usr/local/bin";
366     CHECK(str == fs::path(str, fs::path::format::generic_format));
367     CHECK(str == fs::path(str.begin(), str.end()));
368     CHECK(fs::path(std::wstring(3, 67)) == "CCC");
369     CHECK(str == fs::path(u16str.begin(), u16str.end()));
370     CHECK(str == fs::path(u32str.begin(), u32str.end()));
371 #ifdef GHC_FILESYSTEM_VERSION
372     CHECK(fs::path("///foo/bar") == "/foo/bar");
373     CHECK(fs::path("//foo//bar") == "//foo/bar");
374 #endif
375 #ifdef GHC_OS_WINDOWS
376     CHECK("\\usr\\local\\bin" == fs::path("/usr/local/bin"));
377     CHECK("C:\\usr\\local\\bin" == fs::path("C:\\usr\\local\\bin"));
378 #else
379     CHECK("/usr/local/bin" == fs::path("/usr/local/bin"));
380 #endif
381     if (has_host_root_name_support()) {
382         CHECK("//host/foo/bar" == fs::path("//host/foo/bar"));
383     }
384 
385 #if !defined(GHC_OS_WINDOWS) && !(defined(GCC_VERSION) && GCC_VERSION < 80100) && !defined(USE_STD_FS)
386     std::locale loc;
387     bool testUTF8Locale = false;
388     try {
389         if (const char* lang = std::getenv("LANG")) {
390             loc = std::locale(lang);
391         }
392         else {
393             loc = std::locale("en_US.UTF-8");
394         }
395         std::string name = loc.name();
396         if (name.length() > 5 && (name.substr(name.length() - 5) == "UTF-8" || name.substr(name.length() - 5) == "utf-8")) {
397             testUTF8Locale = true;
398         }
399     }
400     catch (std::runtime_error&) {
401         WARN("Couldn't create an UTF-8 locale!");
402     }
403     if (testUTF8Locale) {
404         CHECK("/usr/local/bin" == fs::path("/usr/local/bin", loc));
405         CHECK(str == fs::path(str.begin(), str.end(), loc));
406         CHECK(str == fs::path(u16str.begin(), u16str.end(), loc));
407         CHECK(str == fs::path(u32str.begin(), u32str.end(), loc));
408     }
409 #endif
410 }
411 
412 TEST_CASE("30.10.8.4.2 path assignments", "[filesystem][path][fs.path.assign]")
413 {
414     fs::path p1{"/foo/bar"};
415     fs::path p2{"/usr/local"};
416     fs::path p3;
417     p3 = p1;
418     REQUIRE(p1 == p3);
419     p3 = fs::path{"/usr/local"};
420     REQUIRE(p2 == p3);
421 #if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
422     p3 = fs::path::string_type{L"/foo/bar"};
423     REQUIRE(p1 == p3);
424     p3.assign(fs::path::string_type{L"/usr/local"});
425     REQUIRE(p2 == p3);
426 #else
427     p3 = fs::path::string_type{"/foo/bar"};
428     REQUIRE(p1 == p3);
429     p3.assign(fs::path::string_type{"/usr/local"});
430     REQUIRE(p2 == p3);
431 #endif
432     p3 = std::u16string(u"/foo/bar");
433     REQUIRE(p1 == p3);
434     p3 = U"/usr/local";
435     REQUIRE(p2 == p3);
436     p3.assign(std::u16string(u"/foo/bar"));
437     REQUIRE(p1 == p3);
438     std::string s{"/usr/local"};
439     p3.assign(s.begin(), s.end());
440     REQUIRE(p2 == p3);
441 }
442 
443 TEST_CASE("30.10.8.4.3 path appends", "[filesystem][path][fs.path.append]")
444 {
445 #ifdef GHC_OS_WINDOWS
446     CHECK(fs::path("foo") / "c:/bar" == "c:/bar");
447     CHECK(fs::path("foo") / "c:" == "c:");
448     CHECK(fs::path("c:") / "" == "c:");
449     CHECK(fs::path("c:foo") / "/bar" == "c:/bar");
450     CHECK(fs::path("c:foo") / "c:bar" == "c:foo/bar");
451 #else
452     CHECK(fs::path("foo") / "" == "foo/");
453     CHECK(fs::path("foo") / "/bar" == "/bar");
454     CHECK(fs::path("/foo") / "/" == "/");
455     if (has_host_root_name_support()) {
456         CHECK(fs::path("//host/foo") / "/bar" == "/bar");
457         CHECK(fs::path("//host") / "/" == "//host/");
458         CHECK(fs::path("//host/foo") / "/" == "/");
459     }
460 #endif
461     CHECK(fs::path("/foo/bar") / "some///other" == "/foo/bar/some/other");
462     fs::path p1{"/tmp/test"};
463     fs::path p2{"foobar.txt"};
464     fs::path p3 = p1 / p2;
465     CHECK("/tmp/test/foobar.txt" == p3);
466     // TODO: append(first, last)
467 }
468 
469 TEST_CASE("30.10.8.4.4 path concatenation", "[filesystem][path][fs.path.concat]")
470 {
471     CHECK((fs::path("foo") += fs::path("bar")) == "foobar");
472     CHECK((fs::path("foo") += fs::path("/bar")) == "foo/bar");
473 
474     CHECK((fs::path("foo") += std::string("bar")) == "foobar");
475     CHECK((fs::path("foo") += std::string("/bar")) == "foo/bar");
476 
477     CHECK((fs::path("foo") += "bar") == "foobar");
478     CHECK((fs::path("foo") += "/bar") == "foo/bar");
479 
480     CHECK((fs::path("foo") += 'b') == "foob");
481     CHECK((fs::path("foo") += '/') == "foo/");
482 
483     CHECK((fs::path("foo") += std::string("bar")) == "foobar");
484     CHECK((fs::path("foo") += std::string("/bar")) == "foo/bar");
485 
486     CHECK((fs::path("foo") += std::u16string(u"bar")) == "foobar");
487     CHECK((fs::path("foo") += std::u16string(u"/bar")) == "foo/bar");
488 
489     CHECK((fs::path("foo") += std::u32string(U"bar")) == "foobar");
490     CHECK((fs::path("foo") += std::u32string(U"/bar")) == "foo/bar");
491 
492     CHECK(fs::path("foo").concat("bar") == "foobar");
493     CHECK(fs::path("foo").concat("/bar") == "foo/bar");
494     std::string bar = "bar";
495     CHECK(fs::path("foo").concat(bar.begin(), bar.end()) == "foobar");
496 #ifndef USE_STD_FS
497     CHECK((fs::path("/foo/bar") += "/some///other") == "/foo/bar/some/other");
498 #endif
499     // TODO: contat(first, last)
500 }
501 
502 TEST_CASE("30.10.8.4.5 path modifiers", "[filesystem][path][fs.path.modifiers]")
503 {
504     fs::path p = fs::path("/foo/bar");
505     p.clear();
506     CHECK(p == "");
507 
508     // make_preferred() is a no-op
509 #ifdef GHC_OS_WINDOWS
510     CHECK(fs::path("foo\\bar") == "foo/bar");
511     CHECK(fs::path("foo\\bar").make_preferred() == "foo/bar");
512 #else
513     CHECK(fs::path("foo\\bar") == "foo\\bar");
514     CHECK(fs::path("foo\\bar").make_preferred() == "foo\\bar");
515 #endif
516     CHECK(fs::path("foo/bar").make_preferred() == "foo/bar");
517 
518     CHECK(fs::path("foo/bar").remove_filename() == "foo/");
519     CHECK(fs::path("foo/").remove_filename() == "foo/");
520     CHECK(fs::path("/foo").remove_filename() == "/");
521     CHECK(fs::path("/").remove_filename() == "/");
522 
523     CHECK(fs::path("/foo").replace_filename("bar") == "/bar");
524     CHECK(fs::path("/").replace_filename("bar") == "/bar");
525     CHECK(fs::path("/foo").replace_filename("b//ar") == "/b/ar");
526 
527     CHECK(fs::path("/foo/bar.txt").replace_extension("odf") == "/foo/bar.odf");
528     CHECK(fs::path("/foo/bar.txt").replace_extension() == "/foo/bar");
529     CHECK(fs::path("/foo/bar").replace_extension("odf") == "/foo/bar.odf");
530     CHECK(fs::path("/foo/bar").replace_extension(".odf") == "/foo/bar.odf");
531     CHECK(fs::path("/foo/bar.").replace_extension(".odf") == "/foo/bar.odf");
532     CHECK(fs::path("/foo/bar/").replace_extension("odf") == "/foo/bar/.odf");
533 
534     fs::path p1 = "foo";
535     fs::path p2 = "bar";
536     p1.swap(p2);
537     CHECK(p1 == "bar");
538     CHECK(p2 == "foo");
539 }
540 
541 TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.path.native.obs]")
542 {
543 #ifdef GHC_OS_WINDOWS
544 #if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
545     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type(L"\u00E4\\\u20AC"));
546     // CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("ä\\€")); // MSVCs returns local DBCS encoding
547 #else
548     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type("\xc3\xa4\\\xe2\x82\xac"));
549     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("\xc3\xa4\\\xe2\x82\xac"));
550     CHECK(!::strcmp(fs::u8path("\xc3\xa4\\\xe2\x82\xac").c_str(), "\xc3\xa4\\\xe2\x82\xac"));
551     CHECK((std::string)fs::u8path("\xc3\xa4\\\xe2\x82\xac") == std::string("\xc3\xa4\\\xe2\x82\xac"));
552 #endif
553     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").wstring() == std::wstring(L"\u00E4\\\u20AC"));
554     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::string("\xc3\xa4\\\xe2\x82\xac"));
555     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u16string() == std::u16string(u"\u00E4\\\u20AC"));
556     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4\\\U000020AC"));
557 #else
558     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").native() == fs::path::string_type(u8"\xc3\xa4/\xe2\x82\xac"));
559     CHECK(!::strcmp(fs::u8path("\xc3\xa4/\xe2\x82\xac").c_str(), u8"\xc3\xa4/\xe2\x82\xac"));
560     CHECK((std::string)fs::u8path("\xc3\xa4/\xe2\x82\xac") == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
561     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
562     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").wstring() == std::wstring(L"ä/€"));
563     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
564     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u16string() == std::u16string(u"\u00E4/\u20AC"));
565     INFO("This check might fail on GCC8 (with \"Illegal byte sequence\") due to not detecting the valid unicode codepoint U+1D11E.");
566     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e").u16string() == std::u16string(u"\u00E4/\u20AC\U0001D11E"));
567     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4/\U000020AC"));
568 #endif
569 }
570 
571 TEST_CASE("30.10.8.4.7 path generic format observers", "[filesystem][path][fs.path.generic.obs]")
572 {
573 #ifdef GHC_OS_WINDOWS
574 #ifndef IS_WCHAR_PATH
575     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_string() == std::string("\xc3\xa4/\xe2\x82\xac"));
576 #endif
577 #ifndef USE_STD_FS
578     auto t = fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_string<char, std::char_traits<char>, TestAllocator<char>>();
579     CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac"));
580 #endif
581     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_wstring() == std::wstring(L"\U000000E4/\U000020AC"));
582     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac"));
583     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC"));
584     CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC"));
585 #else
586     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
587 #ifndef USE_STD_FS
588     auto t = fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string<char, std::char_traits<char>, TestAllocator<char>>();
589     CHECK(t.c_str() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
590 #endif
591     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_wstring() == std::wstring(L"ä/€"));
592     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
593     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC"));
594     CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC"));
595 #endif
596 }
597 
598 TEST_CASE("30.10.8.4.8 path compare", "[filesystem][path][fs.path.compare]")
599 {
600     CHECK(fs::path("/foo/b").compare("/foo/a") > 0);
601     CHECK(fs::path("/foo/b").compare("/foo/b") == 0);
602     CHECK(fs::path("/foo/b").compare("/foo/c") < 0);
603 
604     CHECK(fs::path("/foo/b").compare(std::string("/foo/a")) > 0);
605     CHECK(fs::path("/foo/b").compare(std::string("/foo/b")) == 0);
606     CHECK(fs::path("/foo/b").compare(std::string("/foo/c")) < 0);
607 
608     CHECK(fs::path("/foo/b").compare(fs::path("/foo/a")) > 0);
609     CHECK(fs::path("/foo/b").compare(fs::path("/foo/b")) == 0);
610     CHECK(fs::path("/foo/b").compare(fs::path("/foo/c")) < 0);
611 }
612 
613 TEST_CASE("30.10.8.4.9 path decomposition", "[filesystem][path][fs.path.decompose]")
614 {
615     // root_name()
616     CHECK(fs::path("").root_name() == "");
617     CHECK(fs::path(".").root_name() == "");
618     CHECK(fs::path("..").root_name() == "");
619     CHECK(fs::path("foo").root_name() == "");
620     CHECK(fs::path("/").root_name() == "");
621     CHECK(fs::path("/foo").root_name() == "");
622     CHECK(fs::path("foo/").root_name() == "");
623     CHECK(fs::path("/foo/").root_name() == "");
624     CHECK(fs::path("foo/bar").root_name() == "");
625     CHECK(fs::path("/foo/bar").root_name() == "");
626     CHECK(fs::path("///foo/bar").root_name() == "");
627 #ifdef GHC_OS_WINDOWS
628     CHECK(fs::path("C:/foo").root_name() == "C:");
629     CHECK(fs::path("C:\\foo").root_name() == "C:");
630     CHECK(fs::path("C:foo").root_name() == "C:");
631 #endif
632 
633     // root_directory()
634     CHECK(fs::path("").root_directory() == "");
635     CHECK(fs::path(".").root_directory() == "");
636     CHECK(fs::path("..").root_directory() == "");
637     CHECK(fs::path("foo").root_directory() == "");
638     CHECK(fs::path("/").root_directory() == "/");
639     CHECK(fs::path("/foo").root_directory() == "/");
640     CHECK(fs::path("foo/").root_directory() == "");
641     CHECK(fs::path("/foo/").root_directory() == "/");
642     CHECK(fs::path("foo/bar").root_directory() == "");
643     CHECK(fs::path("/foo/bar").root_directory() == "/");
644     CHECK(fs::path("///foo/bar").root_directory() == "/");
645 #ifdef GHC_OS_WINDOWS
646     CHECK(fs::path("C:/foo").root_directory() == "/");
647     CHECK(fs::path("C:\\foo").root_directory() == "/");
648     CHECK(fs::path("C:foo").root_directory() == "");
649 #endif
650 
651     // root_path()
652     CHECK(fs::path("").root_path() == "");
653     CHECK(fs::path(".").root_path() == "");
654     CHECK(fs::path("..").root_path() == "");
655     CHECK(fs::path("foo").root_path() == "");
656     CHECK(fs::path("/").root_path() == "/");
657     CHECK(fs::path("/foo").root_path() == "/");
658     CHECK(fs::path("foo/").root_path() == "");
659     CHECK(fs::path("/foo/").root_path() == "/");
660     CHECK(fs::path("foo/bar").root_path() == "");
661     CHECK(fs::path("/foo/bar").root_path() == "/");
662     CHECK(fs::path("///foo/bar").root_path() == "/");
663 #ifdef GHC_OS_WINDOWS
664     CHECK(fs::path("C:/foo").root_path() == "C:/");
665     CHECK(fs::path("C:\\foo").root_path() == "C:/");
666     CHECK(fs::path("C:foo").root_path() == "C:");
667 #endif
668 
669     // relative_path()
670     CHECK(fs::path("").relative_path() == "");
671     CHECK(fs::path(".").relative_path() == ".");
672     CHECK(fs::path("..").relative_path() == "..");
673     CHECK(fs::path("foo").relative_path() == "foo");
674     CHECK(fs::path("/").relative_path() == "");
675     CHECK(fs::path("/foo").relative_path() == "foo");
676     CHECK(fs::path("foo/").relative_path() == "foo/");
677     CHECK(fs::path("/foo/").relative_path() == "foo/");
678     CHECK(fs::path("foo/bar").relative_path() == "foo/bar");
679     CHECK(fs::path("/foo/bar").relative_path() == "foo/bar");
680     CHECK(fs::path("///foo/bar").relative_path() == "foo/bar");
681 #ifdef GHC_OS_WINDOWS
682     CHECK(fs::path("C:/foo").relative_path() == "foo");
683     CHECK(fs::path("C:\\foo").relative_path() == "foo");
684     CHECK(fs::path("C:foo").relative_path() == "foo");
685 #endif
686 
687     // parent_path()
688     CHECK(fs::path("").parent_path() == "");
689     CHECK(fs::path(".").parent_path() == "");
690     CHECK(fs::path("..").parent_path() == "");  // unintuitive but as defined in the standard
691     CHECK(fs::path("foo").parent_path() == "");
692     CHECK(fs::path("/").parent_path() == "/");
693     CHECK(fs::path("/foo").parent_path() == "/");
694     CHECK(fs::path("foo/").parent_path() == "foo");
695     CHECK(fs::path("/foo/").parent_path() == "/foo");
696     CHECK(fs::path("foo/bar").parent_path() == "foo");
697     CHECK(fs::path("/foo/bar").parent_path() == "/foo");
698     CHECK(fs::path("///foo/bar").parent_path() == "/foo");
699 #ifdef GHC_OS_WINDOWS
700     CHECK(fs::path("C:/foo").parent_path() == "C:/");
701     CHECK(fs::path("C:\\foo").parent_path() == "C:/");
702     CHECK(fs::path("C:foo").parent_path() == "C:");
703 #endif
704 
705     // filename()
706     CHECK(fs::path("").filename() == "");
707     CHECK(fs::path(".").filename() == ".");
708     CHECK(fs::path("..").filename() == "..");
709     CHECK(fs::path("foo").filename() == "foo");
710     CHECK(fs::path("/").filename() == "");
711     CHECK(fs::path("/foo").filename() == "foo");
712     CHECK(fs::path("foo/").filename() == "");
713     CHECK(fs::path("/foo/").filename() == "");
714     CHECK(fs::path("foo/bar").filename() == "bar");
715     CHECK(fs::path("/foo/bar").filename() == "bar");
716     CHECK(fs::path("///foo/bar").filename() == "bar");
717 #ifdef GHC_OS_WINDOWS
718     CHECK(fs::path("C:/foo").filename() == "foo");
719     CHECK(fs::path("C:\\foo").filename() == "foo");
720     CHECK(fs::path("C:foo").filename() == "foo");
721 #endif
722 
723     // stem()
724     CHECK(fs::path("/foo/bar.txt").stem() == "bar");
725     {
726         fs::path p = "foo.bar.baz.tar";
727         CHECK(p.extension() == ".tar");
728         p = p.stem();
729         CHECK(p.extension() == ".baz");
730         p = p.stem();
731         CHECK(p.extension() == ".bar");
732         p = p.stem();
733         CHECK(p == "foo");
734     }
735     CHECK(fs::path("/foo/.profile").stem() == ".profile");
736     CHECK(fs::path(".bar").stem() == ".bar");
737     CHECK(fs::path("..bar").stem() == ".");
738 
739     // extension()
740     CHECK(fs::path("/foo/bar.txt").extension() == ".txt");
741     CHECK(fs::path("/foo/bar").extension() == "");
742     CHECK(fs::path("/foo/.profile").extension() == "");
743     CHECK(fs::path(".bar").extension() == "");
744     CHECK(fs::path("..bar").extension() == ".bar");
745 
746     if (has_host_root_name_support()) {
747         // //host-based root-names
748         CHECK(fs::path("//host").root_name() == "//host");
749         CHECK(fs::path("//host/foo").root_name() == "//host");
750         CHECK(fs::path("//host").root_directory() == "");
751         CHECK(fs::path("//host/foo").root_directory() == "/");
752         CHECK(fs::path("//host").root_path() == "//host");
753         CHECK(fs::path("//host/foo").root_path() == "//host/");
754         CHECK(fs::path("//host").relative_path() == "");
755         CHECK(fs::path("//host/foo").relative_path() == "foo");
756         CHECK(fs::path("//host").parent_path() == "//host");
757         CHECK(fs::path("//host/foo").parent_path() == "//host/");
758         CHECK(fs::path("//host").filename() == "");
759         CHECK(fs::path("//host/foo").filename() == "foo");
760     }
761 }
762 
763 TEST_CASE("30.10.8.4.10 path query", "[fielsystem][path][fs.path.query]")
764 {
765     // empty
766     CHECK(fs::path("").empty());
767     CHECK(!fs::path("foo").empty());
768 
769     // has_root_path()
770     CHECK(!fs::path("foo").has_root_path());
771     CHECK(!fs::path("foo/bar").has_root_path());
772     CHECK(fs::path("/foo").has_root_path());
773 #ifdef GHC_OS_WINDOWS
774     CHECK(fs::path("C:foo").has_root_path());
775     CHECK(fs::path("C:/foo").has_root_path());
776 #endif
777 
778     // has_root_name()
779     CHECK(!fs::path("foo").has_root_name());
780     CHECK(!fs::path("foo/bar").has_root_name());
781     CHECK(!fs::path("/foo").has_root_name());
782 #ifdef GHC_OS_WINDOWS
783     CHECK(fs::path("C:foo").has_root_name());
784     CHECK(fs::path("C:/foo").has_root_name());
785 #endif
786 
787     // has_root_directory()
788     CHECK(!fs::path("foo").has_root_directory());
789     CHECK(!fs::path("foo/bar").has_root_directory());
790     CHECK(fs::path("/foo").has_root_directory());
791 #ifdef GHC_OS_WINDOWS
792     CHECK(!fs::path("C:foo").has_root_directory());
793     CHECK(fs::path("C:/foo").has_root_directory());
794 #endif
795 
796     // has_relative_path()
797     CHECK(!fs::path("").has_relative_path());
798     CHECK(!fs::path("/").has_relative_path());
799     CHECK(fs::path("/foo").has_relative_path());
800 
801     // has_parent_path()
802     CHECK(!fs::path("").has_parent_path());
803     CHECK(!fs::path(".").has_parent_path());
804     CHECK(!fs::path("..").has_parent_path());  // unintuitive but as defined in the standard
805     CHECK(!fs::path("foo").has_parent_path());
806     CHECK(fs::path("/").has_parent_path());
807     CHECK(fs::path("/foo").has_parent_path());
808     CHECK(fs::path("foo/").has_parent_path());
809     CHECK(fs::path("/foo/").has_parent_path());
810 
811     // has_filename()
812     CHECK(fs::path("foo").has_filename());
813     CHECK(fs::path("foo/bar").has_filename());
814     CHECK(!fs::path("/foo/bar/").has_filename());
815 
816     // has_stem()
817     CHECK(fs::path("foo").has_stem());
818     CHECK(fs::path("foo.bar").has_stem());
819     CHECK(fs::path(".profile").has_stem());
820     CHECK(!fs::path("/foo/").has_stem());
821 
822     // has_extension()
823     CHECK(!fs::path("foo").has_extension());
824     CHECK(fs::path("foo.bar").has_extension());
825     CHECK(!fs::path(".profile").has_extension());
826 
827     // is_absolute()
828     CHECK(!fs::path("foo/bar").is_absolute());
829 #ifdef GHC_OS_WINDOWS
830     CHECK(!fs::path("/foo").is_absolute());
831     CHECK(!fs::path("c:foo").is_absolute());
832     CHECK(fs::path("c:/foo").is_absolute());
833 #else
834     CHECK(fs::path("/foo").is_absolute());
835 #endif
836 
837     // is_relative()
838     CHECK(fs::path("foo/bar").is_relative());
839 #ifdef GHC_OS_WINDOWS
840     CHECK(fs::path("/foo").is_relative());
841     CHECK(fs::path("c:foo").is_relative());
842     CHECK(!fs::path("c:/foo").is_relative());
843 #else
844     CHECK(!fs::path("/foo").is_relative());
845 #endif
846 
847     if (has_host_root_name_support()) {
848         CHECK(fs::path("//host").has_root_name());
849         CHECK(fs::path("//host/foo").has_root_name());
850         CHECK(fs::path("//host").has_root_path());
851         CHECK(fs::path("//host/foo").has_root_path());
852         CHECK(!fs::path("//host").has_root_directory());
853         CHECK(fs::path("//host/foo").has_root_directory());
854         CHECK(!fs::path("//host").has_relative_path());
855         CHECK(fs::path("//host/foo").has_relative_path());
856         CHECK(fs::path("//host/foo").is_absolute());
857         CHECK(!fs::path("//host/foo").is_relative());
858     }
859 }
860 
861 TEST_CASE("30.10.8.4.11 path generation", "[filesystem][path][fs.path.gen]")
862 {
863     // lexically_normal()
864     CHECK(fs::path("foo/./bar/..").lexically_normal() == "foo/");
865     CHECK(fs::path("foo/.///bar/../").lexically_normal() == "foo/");
866     CHECK(fs::path("/foo/../..").lexically_normal() == "/");
867     CHECK(fs::path("foo/..").lexically_normal() == ".");
868     CHECK(fs::path("ab/cd/ef/../../qw").lexically_normal() == "ab/qw");
869     CHECK(fs::path("a/b/../../../c").lexically_normal() == "../c");
870     CHECK(fs::path("../").lexically_normal() == "..");
871 #ifdef GHC_OS_WINDOWS
872     CHECK(fs::path("\\/\\///\\/").lexically_normal() == "/");
873     CHECK(fs::path("a/b/..\\//..///\\/../c\\\\/").lexically_normal() == "../c/");
874     CHECK(fs::path("..a/b/..\\//..///\\/../c\\\\/").lexically_normal() == "../c/");
875     CHECK(fs::path("..\\").lexically_normal() == "..");
876 #endif
877 
878     // lexically_relative()
879     CHECK(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d");
880     CHECK(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c");
881     CHECK(fs::path("a/b/c").lexically_relative("a") == "b/c");
882     CHECK(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
883     CHECK(fs::path("a/b/c").lexically_relative("a/b/c") == ".");
884     CHECK(fs::path("a/b").lexically_relative("c/d") == "../../a/b");
885     CHECK(fs::path("a/b").lexically_relative("a/") == "b");
886     if (has_host_root_name_support()) {
887         CHECK(fs::path("//host1/foo").lexically_relative("//host2.bar") == "");
888     }
889 #ifdef GHC_OS_WINDOWS
890     CHECK(fs::path("c:/foo").lexically_relative("/bar") == "");
891     CHECK(fs::path("c:foo").lexically_relative("c:/bar") == "");
892     CHECK(fs::path("foo").lexically_relative("/bar") == "");
893 #else
894     CHECK(fs::path("/foo").lexically_relative("bar") == "");
895     CHECK(fs::path("foo").lexically_relative("/bar") == "");
896 #endif
897 
898     // lexically_proximate()
899     CHECK(fs::path("/a/d").lexically_proximate("/a/b/c") == "../../d");
900     if (has_host_root_name_support()) {
901         CHECK(fs::path("//host1/a/d").lexically_proximate("//host2/a/b/c") == "//host1/a/d");
902     }
903     CHECK(fs::path("a/d").lexically_proximate("/a/b/c") == "a/d");
904 #ifdef GHC_OS_WINDOWS
905     CHECK(fs::path("c:/a/d").lexically_proximate("c:/a/b/c") == "../../d");
906     CHECK(fs::path("c:/a/d").lexically_proximate("d:/a/b/c") == "c:/a/d");
907     CHECK(fs::path("c:/foo").lexically_proximate("/bar") == "c:/foo");
908     CHECK(fs::path("c:foo").lexically_proximate("c:/bar") == "c:foo");
909     CHECK(fs::path("foo").lexically_proximate("/bar") == "foo");
910 #else
911     CHECK(fs::path("/foo").lexically_proximate("bar") == "/foo");
912     CHECK(fs::path("foo").lexically_proximate("/bar") == "foo");
913 #endif
914 }
915 
iterateResult(const fs::path & path)916 static std::string iterateResult(const fs::path& path)
917 {
918     std::ostringstream result;
919     for (fs::path::const_iterator i = path.begin(); i != path.end(); ++i) {
920         if (i != path.begin()) {
921             result << ",";
922         }
923         result << i->generic_string();
924     }
925     return result.str();
926 }
927 
reverseIterateResult(const fs::path & path)928 static std::string reverseIterateResult(const fs::path& path)
929 {
930     std::ostringstream result;
931     fs::path::const_iterator iter = path.end();
932     bool first = true;
933     if (iter != path.begin()) {
934         do {
935             --iter;
936             if (!first) {
937                 result << ",";
938             }
939             first = false;
940             result << iter->generic_string();
941         } while (iter != path.begin());
942     }
943     return result.str();
944 }
945 
946 TEST_CASE("30.10.8.5 path iterators", "[filesystem][path][fs.path.itr]")
947 {
948     CHECK(iterateResult(fs::path()).empty());
949     CHECK("." == iterateResult(fs::path(".")));
950     CHECK(".." == iterateResult(fs::path("..")));
951     CHECK("foo" == iterateResult(fs::path("foo")));
952     CHECK("/" == iterateResult(fs::path("/")));
953     CHECK("/,foo" == iterateResult(fs::path("/foo")));
954     CHECK("foo," == iterateResult(fs::path("foo/")));
955     CHECK("/,foo," == iterateResult(fs::path("/foo/")));
956     CHECK("foo,bar" == iterateResult(fs::path("foo/bar")));
957     CHECK("/,foo,bar" == iterateResult(fs::path("/foo/bar")));
958     CHECK("/,foo,bar" == iterateResult(fs::path("///foo/bar")));
959     CHECK("/,foo,bar," == iterateResult(fs::path("/foo/bar///")));
960     CHECK("foo,.,bar,..," == iterateResult(fs::path("foo/.///bar/../")));
961 #ifdef GHC_OS_WINDOWS
962     CHECK("C:,/,foo" == iterateResult(fs::path("C:/foo")));
963 #endif
964 
965     CHECK(reverseIterateResult(fs::path()).empty());
966     CHECK("." == reverseIterateResult(fs::path(".")));
967     CHECK(".." == reverseIterateResult(fs::path("..")));
968     CHECK("foo" == reverseIterateResult(fs::path("foo")));
969     CHECK("/" == reverseIterateResult(fs::path("/")));
970     CHECK("foo,/" == reverseIterateResult(fs::path("/foo")));
971     CHECK(",foo" == reverseIterateResult(fs::path("foo/")));
972     CHECK(",foo,/" == reverseIterateResult(fs::path("/foo/")));
973     CHECK("bar,foo" == reverseIterateResult(fs::path("foo/bar")));
974     CHECK("bar,foo,/" == reverseIterateResult(fs::path("/foo/bar")));
975     CHECK("bar,foo,/" == reverseIterateResult(fs::path("///foo/bar")));
976     CHECK(",bar,foo,/" == reverseIterateResult(fs::path("/foo/bar///")));
977     CHECK(",..,bar,.,foo" == reverseIterateResult(fs::path("foo/.///bar/../")));
978 #ifdef GHC_OS_WINDOWS
979     CHECK("foo,/,C:" == reverseIterateResult(fs::path("C:/foo")));
980     CHECK("foo,C:" == reverseIterateResult(fs::path("C:foo")));
981 #endif
982     {
983         fs::path p1 = "/foo/bar/test.txt";
984         fs::path p2;
985         for (auto pe : p1) {
986             p2 /= pe;
987         }
988         CHECK(p1 == p2);
989         CHECK("bar" == *(--fs::path("/foo/bar").end()));
990         auto p = fs::path("/foo/bar");
991         auto pi = p.end();
992         pi--;
993         CHECK("bar" == *pi);
994     }
995 
996     if (has_host_root_name_support()) {
997         CHECK("foo" == *(--fs::path("//host/foo").end()));
998         auto p = fs::path("//host/foo");
999         auto pi = p.end();
1000         pi--;
1001         CHECK("foo" == *pi);
1002         CHECK("//host" == iterateResult(fs::path("//host")));
1003         CHECK("//host,/,foo" == iterateResult(fs::path("//host/foo")));
1004         CHECK("//host" == reverseIterateResult(fs::path("//host")));
1005         CHECK("foo,/,//host" == reverseIterateResult(fs::path("//host/foo")));
1006         {
1007             fs::path p1 = "//host/foo/bar/test.txt";
1008             fs::path p2;
1009             for (auto pe : p1) {
1010                 p2 /= pe;
1011             }
1012             CHECK(p1 == p2);
1013         }
1014     }
1015 }
1016 
1017 TEST_CASE("30.10.8.6 path non-member functions", "[filesystem][path][fs.path.nonmember]")
1018 {
1019     fs::path p1("foo/bar");
1020     fs::path p2("some/other");
1021     fs::swap(p1, p2);
1022     CHECK(p1 == "some/other");
1023     CHECK(p2 == "foo/bar");
1024     CHECK(hash_value(p1));
1025     CHECK(p2 < p1);
1026     CHECK(p2 <= p1);
1027     CHECK(p1 <= p1);
1028     CHECK(!(p1 < p2));
1029     CHECK(!(p1 <= p2));
1030     CHECK(p1 > p2);
1031     CHECK(p1 >= p2);
1032     CHECK(p1 >= p1);
1033     CHECK(!(p2 > p1));
1034     CHECK(!(p2 >= p1));
1035     CHECK(p1 != p2);
1036     CHECK(p1 / p2 == "some/other/foo/bar");
1037 }
1038 
1039 TEST_CASE("30.10.8.6.1 path inserter and extractor", "[filesystem][path][fs.path.io]")
1040 {
1041     {
1042         std::ostringstream os;
1043         os << fs::path("/root/foo bar");
1044 #ifdef GHC_OS_WINDOWS
1045         CHECK(os.str() == "\"\\\\root\\\\foo bar\"");
1046 #else
1047         CHECK(os.str() == "\"/root/foo bar\"");
1048 #endif
1049     }
1050     {
1051         std::ostringstream os;
1052         os << fs::path("/root/foo\"bar");
1053 #ifdef GHC_OS_WINDOWS
1054         CHECK(os.str() == "\"\\\\root\\\\foo\\\"bar\"");
1055 #else
1056         CHECK(os.str() == "\"/root/foo\\\"bar\"");
1057 #endif
1058     }
1059 
1060     {
1061         std::istringstream is("\"/root/foo bar\"");
1062         fs::path p;
1063         is >> p;
1064         CHECK(p == fs::path("/root/foo bar"));
1065         CHECK((is.flags() & std::ios_base::skipws) == std::ios_base::skipws);
1066     }
1067     {
1068         std::istringstream is("\"/root/foo bar\"");
1069         is >> std::noskipws;
1070         fs::path p;
1071         is >> p;
1072         CHECK(p == fs::path("/root/foo bar"));
1073         CHECK((is.flags() & std::ios_base::skipws) != std::ios_base::skipws);
1074     }
1075     {
1076         std::istringstream is("\"/root/foo\\\"bar\"");
1077         fs::path p;
1078         is >> p;
1079         CHECK(p == fs::path("/root/foo\"bar"));
1080     }
1081     {
1082         std::istringstream is("/root/foo");
1083         fs::path p;
1084         is >> p;
1085         CHECK(p == fs::path("/root/foo"));
1086     }
1087 }
1088 
1089 TEST_CASE("30.10.8.6.2 path factory functions", "[filesystem][path][fs.path.factory]")
1090 {
1091     CHECK(fs::u8path("foo/bar") == fs::path("foo/bar"));
1092     CHECK(fs::u8path("foo/bar") == fs::path("foo/bar"));
1093     std::string str("/foo/bar/test.txt");
1094     CHECK(fs::u8path(str.begin(), str.end()) == str);
1095 }
1096 
1097 TEST_CASE("30.10.9 class filesystem_error", "[filesystem][filesystem_error][fs.class.filesystem_error]")
1098 {
1099     std::error_code ec(1, std::system_category());
1100     fs::filesystem_error fse("None", std::error_code());
1101     fse = fs::filesystem_error("Some error", ec);
1102     CHECK(fse.code().value() == 1);
1103     CHECK(!std::string(fse.what()).empty());
1104     CHECK(fse.path1().empty());
1105     CHECK(fse.path2().empty());
1106     fse = fs::filesystem_error("Some error", fs::path("foo/bar"), ec);
1107     CHECK(!std::string(fse.what()).empty());
1108     CHECK(fse.path1() == "foo/bar");
1109     CHECK(fse.path2().empty());
1110     fse = fs::filesystem_error("Some error", fs::path("foo/bar"), fs::path("some/other"), ec);
1111     CHECK(!std::string(fse.what()).empty());
1112     CHECK(fse.path1() == "foo/bar");
1113     CHECK(fse.path2() == "some/other");
1114 }
1115 
1116 TEST_CASE("30.10.10.4 enum class perms", "[filesystem][enum][fs.enum]")
1117 {
1118     CHECK((fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec) == fs::perms::owner_all);
1119     CHECK((fs::perms::group_read | fs::perms::group_write | fs::perms::group_exec) == fs::perms::group_all);
1120     CHECK((fs::perms::others_read | fs::perms::others_write | fs::perms::others_exec) == fs::perms::others_all);
1121     CHECK((fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all) == fs::perms::all);
1122     CHECK((fs::perms::all | fs::perms::set_uid | fs::perms::set_gid | fs::perms::sticky_bit) == fs::perms::mask);
1123 }
1124 
1125 TEST_CASE("30.10.11 class file_status", "[filesystem][file_status][fs.class.file_status]")
1126 {
1127     {
1128         fs::file_status fs;
1129         CHECK(fs.type() == fs::file_type::none);
1130         CHECK(fs.permissions() == fs::perms::unknown);
1131     }
1132     {
1133         fs::file_status fs{fs::file_type::regular};
1134         CHECK(fs.type() == fs::file_type::regular);
1135         CHECK(fs.permissions() == fs::perms::unknown);
1136     }
1137     {
1138         fs::file_status fs{fs::file_type::directory, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec};
1139         CHECK(fs.type() == fs::file_type::directory);
1140         CHECK(fs.permissions() == fs::perms::owner_all);
1141         fs.type(fs::file_type::block);
1142         CHECK(fs.type() == fs::file_type::block);
1143         fs.type(fs::file_type::character);
1144         CHECK(fs.type() == fs::file_type::character);
1145         fs.type(fs::file_type::fifo);
1146         CHECK(fs.type() == fs::file_type::fifo);
1147         fs.type(fs::file_type::symlink);
1148         CHECK(fs.type() == fs::file_type::symlink);
1149         fs.type(fs::file_type::socket);
1150         CHECK(fs.type() == fs::file_type::socket);
1151         fs.permissions(fs.permissions() | fs::perms::group_all | fs::perms::others_all);
1152         CHECK(fs.permissions() == fs::perms::all);
1153     }
1154     {
1155         fs::file_status fst(fs::file_type::regular);
1156         fs::file_status fs(std::move(fst));
1157         CHECK(fs.type() == fs::file_type::regular);
1158         CHECK(fs.permissions() == fs::perms::unknown);
1159     }
1160 }
1161 
1162 TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.dir.entry]")
1163 {
1164     TemporaryDirectory t;
1165     std::error_code ec;
1166     auto de = fs::directory_entry(t.path());
1167     CHECK(de.path() == t.path());
1168     CHECK((fs::path)de == t.path());
1169     CHECK(de.exists());
1170     CHECK(!de.is_block_file());
1171     CHECK(!de.is_character_file());
1172     CHECK(de.is_directory());
1173     CHECK(!de.is_fifo());
1174     CHECK(!de.is_other());
1175     CHECK(!de.is_regular_file());
1176     CHECK(!de.is_socket());
1177     CHECK(!de.is_symlink());
1178     CHECK(de.status().type() == fs::file_type::directory);
1179     ec.clear();
1180     CHECK(de.status(ec).type() == fs::file_type::directory);
1181     CHECK(!ec);
1182     CHECK_NOTHROW(de.refresh());
1183     fs::directory_entry none;
1184     CHECK_THROWS_AS(none.refresh(), fs::filesystem_error);
1185     ec.clear();
1186     CHECK_NOTHROW(none.refresh(ec));
1187     CHECK(ec);
1188     CHECK_THROWS_AS(de.assign(""), fs::filesystem_error);
1189     ec.clear();
1190     CHECK_NOTHROW(de.assign("", ec));
1191     CHECK(ec);
1192     generateFile(t.path() / "foo", 1234);
1193     auto now = fs::file_time_type::clock::now();
1194     CHECK_NOTHROW(de.assign(t.path() / "foo"));
1195     CHECK_NOTHROW(de.assign(t.path() / "foo", ec));
1196     CHECK(!ec);
1197     de = fs::directory_entry(t.path() / "foo");
1198     CHECK(de.path() == t.path() / "foo");
1199     CHECK(de.exists());
1200     CHECK(de.exists(ec));
1201     CHECK(!ec);
1202     CHECK(!de.is_block_file());
1203     CHECK(!de.is_block_file(ec));
1204     CHECK(!ec);
1205     CHECK(!de.is_character_file());
1206     CHECK(!de.is_character_file(ec));
1207     CHECK(!ec);
1208     CHECK(!de.is_directory());
1209     CHECK(!de.is_directory(ec));
1210     CHECK(!ec);
1211     CHECK(!de.is_fifo());
1212     CHECK(!de.is_fifo(ec));
1213     CHECK(!ec);
1214     CHECK(!de.is_other());
1215     CHECK(!de.is_other(ec));
1216     CHECK(!ec);
1217     CHECK(de.is_regular_file());
1218     CHECK(de.is_regular_file(ec));
1219     CHECK(!ec);
1220     CHECK(!de.is_socket());
1221     CHECK(!de.is_socket(ec));
1222     CHECK(!ec);
1223     CHECK(!de.is_symlink());
1224     CHECK(!de.is_symlink(ec));
1225     CHECK(!ec);
1226     CHECK(de.file_size() == 1234);
1227     CHECK(de.file_size(ec) == 1234);
1228     CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(de.last_write_time() - now).count()) < 3);
1229     ec.clear();
1230     CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(de.last_write_time(ec) - now).count()) < 3);
1231     CHECK(!ec);
1232     CHECK(de.hard_link_count() == 1);
1233     CHECK(de.hard_link_count(ec) == 1);
1234     CHECK(!ec);
1235     CHECK_THROWS_AS(de.replace_filename("bar"), fs::filesystem_error);
1236     CHECK_NOTHROW(de.replace_filename("foo"));
1237     ec.clear();
1238     CHECK_NOTHROW(de.replace_filename("bar", ec));
1239     CHECK(ec);
1240     auto de2none = fs::directory_entry();
1241     ec.clear();
1242     CHECK(de2none.hard_link_count(ec) == static_cast<uintmax_t>(-1));
1243     CHECK_THROWS_AS(de2none.hard_link_count(), fs::filesystem_error);
1244     CHECK(ec);
1245     ec.clear();
1246     CHECK_NOTHROW(de2none.last_write_time(ec));
1247     CHECK_THROWS_AS(de2none.last_write_time(), fs::filesystem_error);
1248     CHECK(ec);
1249     ec.clear();
1250     CHECK_THROWS_AS(de2none.file_size(), fs::filesystem_error);
1251     CHECK(de2none.file_size(ec) == static_cast<uintmax_t>(-1));
1252     CHECK(ec);
1253     ec.clear();
1254     CHECK(de2none.status().type() == fs::file_type::not_found);
1255     CHECK(de2none.status(ec).type() == fs::file_type::not_found);
1256     CHECK(ec);
1257     generateFile(t.path() / "a");
1258     generateFile(t.path() / "b");
1259     auto d1 = fs::directory_entry(t.path() / "a");
1260     auto d2 = fs::directory_entry(t.path() / "b");
1261     CHECK(d1 < d2);
1262     CHECK(!(d2 < d1));
1263     CHECK(d1 <= d2);
1264     CHECK(!(d2 <= d1));
1265     CHECK(d2 > d1);
1266     CHECK(!(d1 > d2));
1267     CHECK(d2 >= d1);
1268     CHECK(!(d1 >= d2));
1269     CHECK(d1 != d2);
1270     CHECK(!(d2 != d2));
1271     CHECK(d1 == d1);
1272     CHECK(!(d1 == d2));
1273 }
1274 
1275 TEST_CASE("30.10.13 class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]")
1276 {
1277     {
1278         TemporaryDirectory t;
1279         CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
1280         generateFile(t.path() / "test", 1234);
1281         REQUIRE(fs::directory_iterator(t.path()) != fs::directory_iterator());
1282         auto iter = fs::directory_iterator(t.path());
1283         fs::directory_iterator iter2(iter);
1284         fs::directory_iterator iter3, iter4;
1285         iter3 = iter;
1286         CHECK(iter->path().filename() == "test");
1287         CHECK(iter2->path().filename() == "test");
1288         CHECK(iter3->path().filename() == "test");
1289         iter4 = std::move(iter3);
1290         CHECK(iter4->path().filename() == "test");
1291         CHECK(iter->path() == t.path() / "test");
1292         CHECK(!iter->is_symlink());
1293         CHECK(iter->is_regular_file());
1294         CHECK(!iter->is_directory());
1295         CHECK(iter->file_size() == 1234);
1296         CHECK(++iter == fs::directory_iterator());
1297         CHECK_THROWS_AS(fs::directory_iterator(t.path() / "non-existing"), fs::filesystem_error);
1298         int cnt = 0;
1299         for(auto de : fs::directory_iterator(t.path())) {
1300             ++cnt;
1301         }
1302         CHECK(cnt == 1);
1303     }
1304     if (is_symlink_creation_supported()) {
1305         TemporaryDirectory t;
1306         fs::path td = t.path() / "testdir";
1307         CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
1308         generateFile(t.path() / "test", 1234);
1309         fs::create_directory(td);
1310         REQUIRE_NOTHROW(fs::create_symlink(t.path() / "test", td / "testlink"));
1311         std::error_code ec;
1312         REQUIRE(fs::directory_iterator(td) != fs::directory_iterator());
1313         auto iter = fs::directory_iterator(td);
1314         CHECK(iter->path().filename() == "testlink");
1315         CHECK(iter->path() == td / "testlink");
1316         CHECK(iter->is_symlink());
1317         CHECK(iter->is_regular_file());
1318         CHECK(!iter->is_directory());
1319         CHECK(iter->file_size() == 1234);
1320         CHECK(++iter == fs::directory_iterator());
1321     }
1322     {
1323         // Issue #8: check if resources are freed when iterator reaches end()
1324         TemporaryDirectory t(TempOpt::change_path);
1325         auto p = fs::path("test/");
1326         fs::create_directory(p);
1327         auto iter = fs::directory_iterator(p);
1328         while (iter != fs::directory_iterator()) {
1329             ++iter;
1330         }
1331         CHECK(fs::remove_all(p) == 1);
1332         CHECK_NOTHROW(fs::create_directory(p));
1333     }
1334 }
1335 
1336 TEST_CASE("30.10.14 class recursive_directory_iterator", "[filesystem][recursive_directory_iterator][fs.class.rec.dir.itr]")
1337 {
1338     {
1339         auto iter = fs::recursive_directory_iterator(".");
1340         iter.pop();
1341         CHECK(iter == fs::recursive_directory_iterator());
1342     }
1343     {
1344         TemporaryDirectory t;
1345         CHECK(fs::recursive_directory_iterator(t.path()) == fs::recursive_directory_iterator());
1346         generateFile(t.path() / "test", 1234);
1347         REQUIRE(fs::recursive_directory_iterator(t.path()) != fs::recursive_directory_iterator());
1348         auto iter = fs::recursive_directory_iterator(t.path());
1349         CHECK(iter->path().filename() == "test");
1350         CHECK(iter->path() == t.path() / "test");
1351         CHECK(!iter->is_symlink());
1352         CHECK(iter->is_regular_file());
1353         CHECK(!iter->is_directory());
1354         CHECK(iter->file_size() == 1234);
1355         CHECK(++iter == fs::recursive_directory_iterator());
1356     }
1357 
1358     {
1359         TemporaryDirectory t;
1360         fs::path td = t.path() / "testdir";
1361         fs::create_directories(td);
1362         generateFile(td / "test", 1234);
1363         REQUIRE(fs::recursive_directory_iterator(t.path()) != fs::recursive_directory_iterator());
1364         auto iter = fs::recursive_directory_iterator(t.path());
1365 
1366         CHECK(iter->path().filename() == "testdir");
1367         CHECK(iter->path() == td);
1368         CHECK(!iter->is_symlink());
1369         CHECK(!iter->is_regular_file());
1370         CHECK(iter->is_directory());
1371 
1372         CHECK(++iter != fs::recursive_directory_iterator());
1373 
1374         CHECK(iter->path().filename() == "test");
1375         CHECK(iter->path() == td / "test");
1376         CHECK(!iter->is_symlink());
1377         CHECK(iter->is_regular_file());
1378         CHECK(!iter->is_directory());
1379         CHECK(iter->file_size() == 1234);
1380 
1381         CHECK(++iter == fs::recursive_directory_iterator());
1382     }
1383     {
1384         TemporaryDirectory t;
1385         std::error_code ec;
1386         CHECK(fs::recursive_directory_iterator(t.path(), fs::directory_options::none) == fs::recursive_directory_iterator());
1387         CHECK(fs::recursive_directory_iterator(t.path(), fs::directory_options::none, ec) == fs::recursive_directory_iterator());
1388         CHECK(!ec);
1389         CHECK(fs::recursive_directory_iterator(t.path(), ec) == fs::recursive_directory_iterator());
1390         CHECK(!ec);
1391         generateFile(t.path() / "test");
1392         fs::recursive_directory_iterator rd1(t.path());
1393         CHECK(fs::recursive_directory_iterator(rd1) != fs::recursive_directory_iterator());
1394         fs::recursive_directory_iterator rd2(t.path());
1395         CHECK(fs::recursive_directory_iterator(std::move(rd2)) != fs::recursive_directory_iterator());
1396         fs::recursive_directory_iterator rd3(t.path(), fs::directory_options::skip_permission_denied);
1397         CHECK(rd3.options() == fs::directory_options::skip_permission_denied);
1398         fs::recursive_directory_iterator rd4;
1399         rd4 = std::move(rd3);
1400         CHECK(rd4 != fs::recursive_directory_iterator());
1401         CHECK_NOTHROW(++rd4);
1402         CHECK(rd4 == fs::recursive_directory_iterator());
1403         fs::recursive_directory_iterator rd5;
1404         rd5 = rd4;
1405     }
1406     {
1407         TemporaryDirectory t(TempOpt::change_path);
1408         generateFile("a");
1409         fs::create_directory("d1");
1410         fs::create_directory("d1/d2");
1411         generateFile("d1/b");
1412         generateFile("d1/c");
1413         generateFile("d1/d2/d");
1414         generateFile("e");
1415         auto iter = fs::recursive_directory_iterator(".");
1416         std::multimap<std::string, int> result;
1417         while(iter != fs::recursive_directory_iterator()) {
1418             result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
1419             ++iter;
1420         }
1421         std::stringstream os;
1422         for(auto p : result) {
1423             os << "[" << p.first << "," << p.second << "],";
1424         }
1425         CHECK(os.str() == "[./a,0],[./d1,0],[./d1/b,1],[./d1/c,1],[./d1/d2,1],[./d1/d2/d,2],[./e,0],");
1426     }
1427     {
1428         TemporaryDirectory t(TempOpt::change_path);
1429         generateFile("a");
1430         fs::create_directory("d1");
1431         fs::create_directory("d1/d2");
1432         generateFile("d1/b");
1433         generateFile("d1/c");
1434         generateFile("d1/d2/d");
1435         generateFile("e");
1436         std::multiset<std::string> result;
1437         for(auto de : fs::recursive_directory_iterator(".")) {
1438             result.insert(de.path().generic_string());
1439         }
1440         std::stringstream os;
1441         for(auto p : result) {
1442             os << p << ",";
1443         }
1444         CHECK(os.str() == "./a,./d1,./d1/b,./d1/c,./d1/d2,./d1/d2/d,./e,");
1445     }
1446     {
1447         TemporaryDirectory t(TempOpt::change_path);
1448         generateFile("a");
1449         fs::create_directory("d1");
1450         fs::create_directory("d1/d2");
1451         generateFile("d1/d2/b");
1452         generateFile("e");
1453         auto iter = fs::recursive_directory_iterator(".");
1454         std::multimap<std::string, int> result;
1455         while(iter != fs::recursive_directory_iterator()) {
1456             result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
1457             if(iter->path() == "./d1/d2") {
1458                 iter.disable_recursion_pending();
1459             }
1460             ++iter;
1461         }
1462         std::stringstream os;
1463         for(auto p : result) {
1464             os << "[" << p.first << "," << p.second << "],";
1465         }
1466         CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
1467     }
1468     {
1469         TemporaryDirectory t(TempOpt::change_path);
1470         generateFile("a");
1471         fs::create_directory("d1");
1472         fs::create_directory("d1/d2");
1473         generateFile("d1/d2/b");
1474         generateFile("e");
1475         auto iter = fs::recursive_directory_iterator(".");
1476         std::multimap<std::string, int> result;
1477         while(iter != fs::recursive_directory_iterator()) {
1478             result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
1479             if(iter->path() == "./d1/d2") {
1480                 iter.pop();
1481             }
1482             else {
1483                 ++iter;
1484             }
1485         }
1486         std::stringstream os;
1487         for(auto p : result) {
1488             os << "[" << p.first << "," << p.second << "],";
1489         }
1490         CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
1491     }
1492 }
1493 
1494 TEST_CASE("30.10.15.1 absolute", "[filesystem][operations][fs.op.absolute]")
1495 {
1496     CHECK(fs::absolute("") == fs::current_path() / "");
1497     CHECK(fs::absolute(fs::current_path()) == fs::current_path());
1498     CHECK(fs::absolute(".") == fs::current_path() / ".");
1499     CHECK((fs::absolute("..") == fs::current_path().parent_path() || fs::absolute("..") == fs::current_path() / ".."));
1500     CHECK(fs::absolute("foo") == fs::current_path() / "foo");
1501     std::error_code ec;
1502     CHECK(fs::absolute("", ec) == fs::current_path() / "");
1503     CHECK(!ec);
1504     CHECK(fs::absolute("foo", ec) == fs::current_path() / "foo");
1505     CHECK(!ec);
1506 }
1507 
1508 TEST_CASE("30.10.15.2 canonical", "[filesystem][operations][fs.op.canonical]")
1509 {
1510     CHECK_THROWS_AS(fs::canonical(""), fs::filesystem_error);
1511     {
1512         std::error_code ec;
1513         CHECK(fs::canonical("", ec) == "");
1514         CHECK(ec);
1515     }
1516     CHECK(fs::canonical(fs::current_path()) == fs::current_path());
1517 
1518     CHECK(fs::canonical(".") == fs::current_path());
1519     CHECK(fs::canonical("..") == fs::current_path().parent_path());
1520     CHECK(fs::canonical("/") == fs::current_path().root_path());
1521     CHECK_THROWS_AS(fs::canonical("foo"), fs::filesystem_error);
1522     {
1523         std::error_code ec;
1524         CHECK_NOTHROW(fs::canonical("foo", ec));
1525         CHECK(ec);
1526     }
1527     {
1528         TemporaryDirectory t(TempOpt::change_path);
1529         auto dir = t.path() / "d0";
1530         fs::create_directories(dir / "d1");
1531         generateFile(dir / "f0");
1532         fs::path rel(dir.filename());
1533         CHECK(fs::canonical(dir) == dir);
1534         CHECK(fs::canonical(rel) == dir);
1535         CHECK(fs::canonical(dir / "f0") == dir / "f0");
1536         CHECK(fs::canonical(rel / "f0") == dir / "f0");
1537         CHECK(fs::canonical(rel / "./f0") == dir / "f0");
1538         CHECK(fs::canonical(rel / "d1/../f0") == dir / "f0");
1539     }
1540 
1541     if (is_symlink_creation_supported()) {
1542         TemporaryDirectory t(TempOpt::change_path);
1543         fs::create_directory(t.path() / "dir1");
1544         generateFile(t.path() / "dir1/test1");
1545         fs::create_directory(t.path() / "dir2");
1546         fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym");
1547         CHECK(fs::canonical(t.path() / "dir2/dirSym/test1") == t.path() / "dir1/test1");
1548     }
1549 }
1550 
1551 TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]")
1552 {
1553     {
1554         TemporaryDirectory t(TempOpt::change_path);
1555         std::error_code ec;
1556         fs::create_directory("dir1");
1557         generateFile("dir1/file1");
1558         generateFile("dir1/file2");
1559         fs::create_directory("dir1/dir2");
1560         generateFile("dir1/dir2/file3");
1561         CHECK_NOTHROW(fs::copy("dir1", "dir3"));
1562         CHECK(fs::exists("dir3/file1"));
1563         CHECK(fs::exists("dir3/file2"));
1564         CHECK(!fs::exists("dir3/dir2"));
1565         CHECK_NOTHROW(fs::copy("dir1", "dir4", fs::copy_options::recursive, ec));
1566         CHECK(!ec);
1567         CHECK(fs::exists("dir4/file1"));
1568         CHECK(fs::exists("dir4/file2"));
1569         CHECK(fs::exists("dir4/dir2/file3"));
1570         fs::create_directory("dir5");
1571         generateFile("dir5/file1");
1572         CHECK_THROWS_AS(fs::copy("dir1/file1", "dir5/file1"), fs::filesystem_error);
1573         CHECK_NOTHROW(fs::copy("dir1/file1", "dir5/file1", fs::copy_options::skip_existing));
1574     }
1575     if (is_symlink_creation_supported()) {
1576         TemporaryDirectory t(TempOpt::change_path);
1577         std::error_code ec;
1578         fs::create_directory("dir1");
1579         generateFile("dir1/file1");
1580         generateFile("dir1/file2");
1581         fs::create_directory("dir1/dir2");
1582         generateFile("dir1/dir2/file3");
1583 #ifdef TEST_LWG_2682_BEHAVIOUR
1584         REQUIRE_THROWS_AS(fs::copy("dir1", "dir3", fs::copy_options::create_symlinks | fs::copy_options::recursive), fs::filesystem_error);
1585 #else
1586         REQUIRE_NOTHROW(fs::copy("dir1", "dir3", fs::copy_options::create_symlinks | fs::copy_options::recursive));
1587         CHECK(!ec);
1588         CHECK(fs::exists("dir3/file1"));
1589         CHECK(fs::is_symlink("dir3/file1"));
1590         CHECK(fs::exists("dir3/file2"));
1591         CHECK(fs::is_symlink("dir3/file2"));
1592         CHECK(fs::exists("dir3/dir2/file3"));
1593         CHECK(fs::is_symlink("dir3/dir2/file3"));
1594 #endif
1595     }
1596     {
1597         TemporaryDirectory t(TempOpt::change_path);
1598         std::error_code ec;
1599         fs::create_directory("dir1");
1600         generateFile("dir1/file1");
1601         generateFile("dir1/file2");
1602         fs::create_directory("dir1/dir2");
1603         generateFile("dir1/dir2/file3");
1604         auto f1hl = fs::hard_link_count("dir1/file1");
1605         auto f2hl = fs::hard_link_count("dir1/file2");
1606         auto f3hl = fs::hard_link_count("dir1/dir2/file3");
1607         CHECK_NOTHROW(fs::copy("dir1", "dir3", fs::copy_options::create_hard_links | fs::copy_options::recursive, ec));
1608         REQUIRE(!ec);
1609         CHECK(fs::exists("dir3/file1"));
1610         CHECK(fs::hard_link_count("dir1/file1") == f1hl + 1);
1611         CHECK(fs::exists("dir3/file2"));
1612         CHECK(fs::hard_link_count("dir1/file2") == f2hl + 1);
1613         CHECK(fs::exists("dir3/dir2/file3"));
1614         CHECK(fs::hard_link_count("dir1/dir2/file3") == f3hl + 1);
1615     }
1616 }
1617 
1618 TEST_CASE("30.10.15.4 copy_file", "[filesystem][operations][fs.op.copy_file]")
1619 {
1620     TemporaryDirectory t(TempOpt::change_path);
1621     std::error_code ec;
1622     generateFile("foo", 100);
1623     CHECK(!fs::exists("bar"));
1624     CHECK(fs::copy_file("foo", "bar"));
1625     CHECK(fs::exists("bar"));
1626     CHECK(fs::file_size("foo") == fs::file_size("bar"));
1627     CHECK(fs::copy_file("foo", "bar2", ec));
1628     CHECK(!ec);
1629     std::this_thread::sleep_for(std::chrono::seconds(1));
1630     generateFile("foo2", 200);
1631     CHECK(fs::copy_file("foo2", "bar", fs::copy_options::update_existing));
1632     CHECK(fs::file_size("bar") == 200);
1633     CHECK(!fs::copy_file("foo", "bar", fs::copy_options::update_existing));
1634     CHECK(fs::file_size("bar") == 200);
1635     CHECK(fs::copy_file("foo", "bar", fs::copy_options::overwrite_existing));
1636     CHECK(fs::file_size("bar") == 100);
1637     CHECK_THROWS_AS(fs::copy_file("foobar", "foobar2"), fs::filesystem_error);
1638     CHECK_NOTHROW(fs::copy_file("foobar", "foobar2", ec));
1639     CHECK(ec);
1640     CHECK(!fs::exists("foobar"));
1641 }
1642 
1643 TEST_CASE("30.10.15.5 copy_symlink", "[filesystem][operations][fs.op.copy_symlink]")
1644 {
1645     TemporaryDirectory t(TempOpt::change_path);
1646     std::error_code ec;
1647     generateFile("foo");
1648     fs::create_directory("dir");
1649     if (is_symlink_creation_supported()) {
1650         fs::create_symlink("foo", "sfoo");
1651         fs::create_directory_symlink("dir", "sdir");
1652         CHECK_NOTHROW(fs::copy_symlink("sfoo", "sfooc"));
1653         CHECK(fs::exists("sfooc"));
1654         CHECK_NOTHROW(fs::copy_symlink("sfoo", "sfooc2", ec));
1655         CHECK(fs::exists("sfooc2"));
1656         CHECK(!ec);
1657         CHECK_NOTHROW(fs::copy_symlink("sdir", "sdirc"));
1658         CHECK(fs::exists("sdirc"));
1659         CHECK_NOTHROW(fs::copy_symlink("sdir", "sdirc2", ec));
1660         CHECK(fs::exists("sdirc2"));
1661         CHECK(!ec);
1662     }
1663     CHECK_THROWS_AS(fs::copy_symlink("bar", "barc"), fs::filesystem_error);
1664     CHECK_NOTHROW(fs::copy_symlink("bar", "barc", ec));
1665     CHECK(ec);
1666 }
1667 
1668 TEST_CASE("30.10.15.6 create_directories", "[filesystem][operations][fs.op.create_directories]")
1669 {
1670     TemporaryDirectory t;
1671     fs::path p = t.path() / "testdir";
1672     fs::path p2 = p / "nested";
1673     REQUIRE(!fs::exists(p));
1674     REQUIRE(!fs::exists(p2));
1675     CHECK(fs::create_directories(p2));
1676     CHECK(fs::is_directory(p));
1677     CHECK(fs::is_directory(p2));
1678     CHECK(!fs::create_directories(p2));
1679 #ifdef TEST_LWG_2935_BEHAVIOUR
1680     INFO("This test expects LWG #2935 result conformance.");
1681     p = t.path() / "testfile";
1682     generateFile(p);
1683     CHECK(fs::is_regular_file(p));
1684     CHECK(!fs::is_directory(p));
1685     bool created = false;
1686     CHECK_NOTHROW((created = fs::create_directories(p)));
1687     CHECK(!created);
1688     CHECK(fs::is_regular_file(p));
1689     CHECK(!fs::is_directory(p));
1690     std::error_code ec;
1691     CHECK_NOTHROW((created = fs::create_directories(p, ec)));
1692     CHECK(!created);
1693     CHECK(!ec);
1694     CHECK(fs::is_regular_file(p));
1695     CHECK(!fs::is_directory(p));
1696     CHECK(!fs::create_directories(p, ec));
1697 #else
1698     INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)");
1699     p = t.path() / "testfile";
1700     generateFile(p);
1701     CHECK(fs::is_regular_file(p));
1702     CHECK(!fs::is_directory(p));
1703     CHECK_THROWS_AS(fs::create_directories(p), fs::filesystem_error);
1704     CHECK(fs::is_regular_file(p));
1705     CHECK(!fs::is_directory(p));
1706     std::error_code ec;
1707     CHECK_NOTHROW(fs::create_directories(p, ec));
1708     CHECK(ec);
1709     CHECK(fs::is_regular_file(p));
1710     CHECK(!fs::is_directory(p));
1711     CHECK(!fs::create_directories(p, ec));
1712 #endif
1713 }
1714 
1715 TEST_CASE("30.10.15.7 create_directory", "[filesystem][operations][fs.op.create_directory]")
1716 {
1717     TemporaryDirectory t;
1718     fs::path p = t.path() / "testdir";
1719     REQUIRE(!fs::exists(p));
1720     CHECK(fs::create_directory(p));
1721     CHECK(fs::is_directory(p));
1722     CHECK(!fs::is_regular_file(p));
1723     CHECK(fs::create_directory(p / "nested", p));
1724     CHECK(fs::is_directory(p / "nested"));
1725     CHECK(!fs::is_regular_file(p / "nested"));
1726 #ifdef TEST_LWG_2935_BEHAVIOUR
1727     INFO("This test expects LWG #2935 result conformance.");
1728     p = t.path() / "testfile";
1729     generateFile(p);
1730     CHECK(fs::is_regular_file(p));
1731     CHECK(!fs::is_directory(p));
1732     bool created = false;
1733     CHECK_NOTHROW((created = fs::create_directory(p)));
1734     CHECK(!created);
1735     CHECK(fs::is_regular_file(p));
1736     CHECK(!fs::is_directory(p));
1737     std::error_code ec;
1738     CHECK_NOTHROW((created = fs::create_directory(p, ec)));
1739     CHECK(!created);
1740     CHECK(!ec);
1741     CHECK(fs::is_regular_file(p));
1742     CHECK(!fs::is_directory(p));
1743     CHECK(!fs::create_directories(p, ec));
1744 #else
1745     INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)");
1746     p = t.path() / "testfile";
1747     generateFile(p);
1748     CHECK(fs::is_regular_file(p));
1749     CHECK(!fs::is_directory(p));
1750     REQUIRE_THROWS_AS(fs::create_directory(p), fs::filesystem_error);
1751     CHECK(fs::is_regular_file(p));
1752     CHECK(!fs::is_directory(p));
1753     std::error_code ec;
1754     REQUIRE_NOTHROW(fs::create_directory(p, ec));
1755     CHECK(ec);
1756     CHECK(fs::is_regular_file(p));
1757     CHECK(!fs::is_directory(p));
1758     CHECK(!fs::create_directory(p, ec));
1759 #endif
1760 }
1761 
1762 TEST_CASE("30.10.15.8 create_directory_symlink", "[filesystem][operations][fs.op.create_directory_symlink]")
1763 {
1764     if (is_symlink_creation_supported()) {
1765         TemporaryDirectory t;
1766         fs::create_directory(t.path() / "dir1");
1767         generateFile(t.path() / "dir1/test1");
1768         fs::create_directory(t.path() / "dir2");
1769         fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym");
1770         CHECK(fs::exists(t.path() / "dir2/dirSym"));
1771         CHECK(fs::is_symlink(t.path() / "dir2/dirSym"));
1772         CHECK(fs::exists(t.path() / "dir2/dirSym/test1"));
1773         CHECK(fs::is_regular_file(t.path() / "dir2/dirSym/test1"));
1774         CHECK_THROWS_AS(fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym"), fs::filesystem_error);
1775         std::error_code ec;
1776         CHECK_NOTHROW(fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym", ec));
1777         CHECK(ec);
1778     }
1779 }
1780 
1781 TEST_CASE("30.10.15.9 create_hard_link", "[filesystem][operations][fs.op.create_hard_link]")
1782 {
1783     TemporaryDirectory t(TempOpt::change_path);
1784     std::error_code ec;
1785     generateFile("foo", 1234);
1786     CHECK_NOTHROW(fs::create_hard_link("foo", "bar"));
1787     CHECK(fs::exists("bar"));
1788     CHECK(!fs::is_symlink("bar"));
1789     CHECK_NOTHROW(fs::create_hard_link("foo", "bar2", ec));
1790     CHECK(fs::exists("bar2"));
1791     CHECK(!fs::is_symlink("bar2"));
1792     CHECK(!ec);
1793     CHECK_THROWS_AS(fs::create_hard_link("nofoo", "bar"), fs::filesystem_error);
1794     CHECK_NOTHROW(fs::create_hard_link("nofoo", "bar", ec));
1795     CHECK(ec);
1796 }
1797 
1798 TEST_CASE("30.10.15.10 create_symlink", "[filesystem][operations][fs.op.create_symlink]")
1799 {
1800     if (is_symlink_creation_supported()) {
1801         TemporaryDirectory t;
1802         fs::create_directory(t.path() / "dir1");
1803         generateFile(t.path() / "dir1/test1");
1804         fs::create_directory(t.path() / "dir2");
1805         fs::create_symlink(t.path() / "dir1/test1", t.path() / "dir2/fileSym");
1806         CHECK(fs::exists(t.path() / "dir2/fileSym"));
1807         CHECK(fs::is_symlink(t.path() / "dir2/fileSym"));
1808         CHECK(fs::exists(t.path() / "dir2/fileSym"));
1809         CHECK(fs::is_regular_file(t.path() / "dir2/fileSym"));
1810         CHECK_THROWS_AS(fs::create_symlink(t.path() / "dir1", t.path() / "dir2/fileSym"), fs::filesystem_error);
1811         std::error_code ec;
1812         CHECK_NOTHROW(fs::create_symlink(t.path() / "dir1", t.path() / "dir2/fileSym", ec));
1813         CHECK(ec);
1814     }
1815 }
1816 
1817 TEST_CASE("30.10.15.11 current_path", "[filesystem][operations][fs.op.current_path]")
1818 {
1819     TemporaryDirectory t;
1820     std::error_code ec;
1821     fs::path p1 = fs::current_path();
1822     CHECK_NOTHROW(fs::current_path(t.path()));
1823     CHECK(p1 != fs::current_path());
1824     CHECK_NOTHROW(fs::current_path(p1, ec));
1825     CHECK(!ec);
1826     CHECK_THROWS_AS(fs::current_path(t.path() / "foo"), fs::filesystem_error);
1827     CHECK(p1 == fs::current_path());
1828     CHECK_NOTHROW(fs::current_path(t.path() / "foo", ec));
1829     CHECK(ec);
1830 }
1831 
1832 TEST_CASE("30.10.15.12 equivalent", "[filesystem][operations][fs.op.equivalent]")
1833 {
1834     TemporaryDirectory t(TempOpt::change_path);
1835     generateFile("foo", 1234);
1836     CHECK(fs::equivalent(t.path() / "foo", "foo"));
1837     if (is_symlink_creation_supported()) {
1838         std::error_code ec(42, std::system_category());
1839         fs::create_symlink("foo", "foo2");
1840         CHECK(fs::equivalent("foo", "foo2"));
1841         CHECK(fs::equivalent("foo", "foo2", ec));
1842         CHECK(!ec);
1843     }
1844 #ifdef TEST_LWG_2937_BEHAVIOUR
1845     INFO("This test expects LWG #2937 result conformance.");
1846     std::error_code ec;
1847     bool result = false;
1848     REQUIRE_THROWS_AS(fs::equivalent("foo", "foo3"), fs::filesystem_error);
1849     CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec));
1850     CHECK(!result);
1851     CHECK(ec);
1852     ec.clear();
1853     CHECK_THROWS_AS(fs::equivalent("foo3", "foo"), fs::filesystem_error);
1854     CHECK_NOTHROW(result = fs::equivalent("foo3", "foo", ec));
1855     CHECK(!result);
1856     CHECK(ec);
1857     ec.clear();
1858     CHECK_THROWS_AS(fs::equivalent("foo3", "foo4"), fs::filesystem_error);
1859     CHECK_NOTHROW(result = fs::equivalent("foo3", "foo4", ec));
1860     CHECK(!result);
1861     CHECK(ec);
1862 #else
1863     INFO("This test expects conformance predating LWG #2937 result.");
1864     std::error_code ec;
1865     bool result = false;
1866     REQUIRE_NOTHROW(result = fs::equivalent("foo", "foo3"));
1867     CHECK(!result);
1868     CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec));
1869     CHECK(!result);
1870     CHECK(!ec);
1871     ec.clear();
1872     CHECK_NOTHROW(result = fs::equivalent("foo3", "foo"));
1873     CHECK(!result);
1874     CHECK_NOTHROW(result = fs::equivalent("foo3", "foo", ec));
1875     CHECK(!result);
1876     CHECK(!ec);
1877     ec.clear();
1878     CHECK_THROWS_AS(result = fs::equivalent("foo4", "foo3"), fs::filesystem_error);
1879     CHECK(!result);
1880     CHECK_NOTHROW(result = fs::equivalent("foo4", "foo3", ec));
1881     CHECK(!result);
1882     CHECK(ec);
1883 #endif
1884 }
1885 
1886 TEST_CASE("30.10.15.13 exists", "[filesystem][operations][fs.op.exists]")
1887 {
1888     TemporaryDirectory t(TempOpt::change_path);
1889     std::error_code ec;
1890     CHECK(!fs::exists(""));
1891     CHECK(!fs::exists("foo"));
1892     CHECK(!fs::exists("foo", ec));
1893     CHECK(!ec);
1894     ec = std::error_code(42, std::system_category());
1895     CHECK(!fs::exists("foo", ec));
1896     CHECK(!ec);
1897     ec.clear();
1898     CHECK(fs::exists(t.path()));
1899     CHECK(fs::exists(t.path(), ec));
1900     CHECK(!ec);
1901     ec = std::error_code(42, std::system_category());
1902     CHECK(fs::exists(t.path(), ec));
1903     CHECK(!ec);
1904 }
1905 
1906 TEST_CASE("30.10.15.14 file_size", "[filesystem][operations][fs.op.file_size]")
1907 {
1908     TemporaryDirectory t(TempOpt::change_path);
1909     std::error_code ec;
1910     generateFile("foo", 0);
1911     generateFile("bar", 1234);
1912     CHECK(fs::file_size("foo") == 0);
1913     ec = std::error_code(42, std::system_category());
1914     CHECK(fs::file_size("foo", ec) == 0);
1915     CHECK(!ec);
1916     ec.clear();
1917     CHECK(fs::file_size("bar") == 1234);
1918     ec = std::error_code(42, std::system_category());
1919     CHECK(fs::file_size("bar", ec) == 1234);
1920     CHECK(!ec);
1921     ec.clear();
1922     CHECK_THROWS_AS(fs::file_size("foobar"), fs::filesystem_error);
1923     CHECK(fs::file_size("foobar", ec) == static_cast<uintmax_t>(-1));
1924     CHECK(ec);
1925     ec.clear();
1926 }
1927 
1928 TEST_CASE("30.10.15.15 hard_link_count", "[filesystem][operations][fs.op.hard_link_count]")
1929 {
1930     TemporaryDirectory t(TempOpt::change_path);
1931     std::error_code ec;
1932 #ifdef GHC_OS_WINDOWS
1933     // windows doesn't implement "."/".." as hardlinks, so it
1934     // starts with 1 and subdirectories don't change the count
1935     CHECK(fs::hard_link_count(t.path()) == 1);
1936     fs::create_directory("dir");
1937     CHECK(fs::hard_link_count(t.path()) == 1);
1938 #else
1939     // unix/bsd/linux typically implements "."/".." as hardlinks
1940     // so an empty dir has 2 (from parent and the ".") and
1941     // adding a subdirectory adds one due to its ".."
1942     CHECK(fs::hard_link_count(t.path()) == 2);
1943     fs::create_directory("dir");
1944     CHECK(fs::hard_link_count(t.path()) == 3);
1945 #endif
1946     generateFile("foo");
1947     CHECK(fs::hard_link_count(t.path() / "foo") == 1);
1948     ec = std::error_code(42, std::system_category());
1949     CHECK(fs::hard_link_count(t.path() / "foo", ec) == 1);
1950     CHECK(!ec);
1951     CHECK_THROWS_AS(fs::hard_link_count(t.path() / "bar"), fs::filesystem_error);
1952     CHECK_NOTHROW(fs::hard_link_count(t.path() / "bar", ec));
1953     CHECK(ec);
1954     ec.clear();
1955 }
1956 
1957 class FileTypeMixFixture
1958 {
1959 public:
FileTypeMixFixture()1960     FileTypeMixFixture()
1961         : _t(TempOpt::change_path)
1962         , _hasFifo(false)
1963         , _hasSocket(false)
1964     {
1965         generateFile("regular");
1966         fs::create_directory("directory");
1967         if (is_symlink_creation_supported()) {
1968             fs::create_symlink("regular", "file_symlink");
1969             fs::create_directory_symlink("directory", "dir_symlink");
1970         }
1971 #ifndef GHC_OS_WINDOWS
1972         REQUIRE(::mkfifo("fifo", 0644) == 0);
1973         _hasFifo = true;
1974         struct ::sockaddr_un addr;
1975         addr.sun_family = AF_UNIX;
1976         std::strncpy(addr.sun_path, "socket", sizeof(addr.sun_path));
1977         int fd = socket(PF_UNIX, SOCK_STREAM, 0);
1978         bind(fd, (struct sockaddr*)&addr, sizeof addr);
1979         _hasSocket = true;
1980 #endif
1981     }
1982 
~FileTypeMixFixture()1983     ~FileTypeMixFixture() {}
1984 
has_fifo() const1985     bool has_fifo() const { return _hasFifo; }
1986 
has_socket() const1987     bool has_socket() const { return _hasSocket; }
1988 
block_path() const1989     fs::path block_path() const
1990     {
1991         std::error_code ec;
1992         if (fs::exists("/dev/sda", ec)) {
1993             return "/dev/sda";
1994         }
1995         else if (fs::exists("/dev/disk0", ec)) {
1996             return "/dev/disk0";
1997         }
1998         return fs::path();
1999     }
2000 
character_path() const2001     fs::path character_path() const
2002     {
2003         std::error_code ec;
2004         if (fs::exists("/dev/null", ec)) {
2005             return "/dev/null";
2006         }
2007         else if (fs::exists("NUL", ec)) {
2008             return "NUL";
2009         }
2010         return fs::path();
2011     }
temp_path() const2012     fs::path temp_path() const { return _t.path(); }
2013 
2014 private:
2015     TemporaryDirectory _t;
2016     bool _hasFifo;
2017     bool _hasSocket;
2018 };
2019 
2020 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.16 is_block_file", "[filesystem][operations][fs.op.is_block_file]")
2021 {
2022     std::error_code ec;
2023     CHECK(!fs::is_block_file("directory"));
2024     CHECK(!fs::is_block_file("regular"));
2025     if (is_symlink_creation_supported()) {
2026         CHECK(!fs::is_block_file("dir_symlink"));
2027         CHECK(!fs::is_block_file("file_symlink"));
2028     }
2029     CHECK((has_fifo() ? !fs::is_block_file("fifo") : true));
2030     CHECK((has_socket() ? !fs::is_block_file("socket") : true));
2031     CHECK((block_path().empty() ? true : fs::is_block_file(block_path())));
2032     CHECK((character_path().empty() ? true : !fs::is_block_file(character_path())));
2033     CHECK_NOTHROW(fs::is_block_file("notfound"));
2034     CHECK_NOTHROW(fs::is_block_file("notfound", ec));
2035     CHECK(ec);
2036     ec.clear();
2037     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::none)));
2038     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::not_found)));
2039     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::regular)));
2040     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::directory)));
2041     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::symlink)));
2042     CHECK(fs::is_block_file(fs::file_status(fs::file_type::block)));
2043     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::character)));
2044     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::fifo)));
2045     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::socket)));
2046     CHECK(!fs::is_block_file(fs::file_status(fs::file_type::unknown)));
2047 }
2048 
2049 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.17 is_character_file", "[filesystem][operations][fs.op.is_character_file]")
2050 {
2051     std::error_code ec;
2052     CHECK(!fs::is_character_file("directory"));
2053     CHECK(!fs::is_character_file("regular"));
2054     if (is_symlink_creation_supported()) {
2055         CHECK(!fs::is_character_file("dir_symlink"));
2056         CHECK(!fs::is_character_file("file_symlink"));
2057     }
2058     CHECK((has_fifo() ? !fs::is_character_file("fifo") : true));
2059     CHECK((has_socket() ? !fs::is_character_file("socket") : true));
2060     CHECK((block_path().empty() ? true : !fs::is_character_file(block_path())));
2061     CHECK((character_path().empty() ? true : fs::is_character_file(character_path())));
2062     CHECK_NOTHROW(fs::is_character_file("notfound"));
2063     CHECK_NOTHROW(fs::is_character_file("notfound", ec));
2064     CHECK(ec);
2065     ec.clear();
2066     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::none)));
2067     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::not_found)));
2068     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::regular)));
2069     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::directory)));
2070     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::symlink)));
2071     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::block)));
2072     CHECK(fs::is_character_file(fs::file_status(fs::file_type::character)));
2073     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::fifo)));
2074     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::socket)));
2075     CHECK(!fs::is_character_file(fs::file_status(fs::file_type::unknown)));
2076 }
2077 
2078 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.18 is_directory", "[filesystem][operations][fs.op.is_directory]")
2079 {
2080     std::error_code ec;
2081     CHECK(fs::is_directory("directory"));
2082     CHECK(!fs::is_directory("regular"));
2083     if (is_symlink_creation_supported()) {
2084         CHECK(fs::is_directory("dir_symlink"));
2085         CHECK(!fs::is_directory("file_symlink"));
2086     }
2087     CHECK((has_fifo() ? !fs::is_directory("fifo") : true));
2088     CHECK((has_socket() ? !fs::is_directory("socket") : true));
2089     CHECK((block_path().empty() ? true : !fs::is_directory(block_path())));
2090     CHECK((character_path().empty() ? true : !fs::is_directory(character_path())));
2091     CHECK_NOTHROW(fs::is_directory("notfound"));
2092     CHECK_NOTHROW(fs::is_directory("notfound", ec));
2093     CHECK(ec);
2094     ec.clear();
2095     CHECK(!fs::is_directory(fs::file_status(fs::file_type::none)));
2096     CHECK(!fs::is_directory(fs::file_status(fs::file_type::not_found)));
2097     CHECK(!fs::is_directory(fs::file_status(fs::file_type::regular)));
2098     CHECK(fs::is_directory(fs::file_status(fs::file_type::directory)));
2099     CHECK(!fs::is_directory(fs::file_status(fs::file_type::symlink)));
2100     CHECK(!fs::is_directory(fs::file_status(fs::file_type::block)));
2101     CHECK(!fs::is_directory(fs::file_status(fs::file_type::character)));
2102     CHECK(!fs::is_directory(fs::file_status(fs::file_type::fifo)));
2103     CHECK(!fs::is_directory(fs::file_status(fs::file_type::socket)));
2104     CHECK(!fs::is_directory(fs::file_status(fs::file_type::unknown)));
2105 }
2106 
2107 TEST_CASE("30.10.15.19 is_empty", "[filesystem][operations][fs.op.is_empty]")
2108 {
2109     TemporaryDirectory t(TempOpt::change_path);
2110     std::error_code ec;
2111     CHECK(fs::is_empty(t.path()));
2112     CHECK(fs::is_empty(t.path(), ec));
2113     CHECK(!ec);
2114     generateFile("foo", 0);
2115     generateFile("bar", 1234);
2116     CHECK(fs::is_empty("foo"));
2117     CHECK(fs::is_empty("foo", ec));
2118     CHECK(!ec);
2119     CHECK(!fs::is_empty("bar"));
2120     CHECK(!fs::is_empty("bar", ec));
2121     CHECK(!ec);
2122     CHECK_THROWS_AS(fs::is_empty("foobar"), fs::filesystem_error);
2123     bool result = false;
2124     CHECK_NOTHROW(result = fs::is_empty("foobar", ec));
2125     CHECK(!result);
2126     CHECK(ec);
2127 }
2128 
2129 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.20 is_fifo", "[filesystem][operations][fs.op.is_fifo]")
2130 {
2131     std::error_code ec;
2132     CHECK(!fs::is_fifo("directory"));
2133     CHECK(!fs::is_fifo("regular"));
2134     if (is_symlink_creation_supported()) {
2135         CHECK(!fs::is_fifo("dir_symlink"));
2136         CHECK(!fs::is_fifo("file_symlink"));
2137     }
2138     CHECK((has_fifo() ? fs::is_fifo("fifo") : true));
2139     CHECK((has_socket() ? !fs::is_fifo("socket") : true));
2140     CHECK((block_path().empty() ? true : !fs::is_fifo(block_path())));
2141     CHECK((character_path().empty() ? true : !fs::is_fifo(character_path())));
2142     CHECK_NOTHROW(fs::is_fifo("notfound"));
2143     CHECK_NOTHROW(fs::is_fifo("notfound", ec));
2144     CHECK(ec);
2145     ec.clear();
2146     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::none)));
2147     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::not_found)));
2148     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::regular)));
2149     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::directory)));
2150     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::symlink)));
2151     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::block)));
2152     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::character)));
2153     CHECK(fs::is_fifo(fs::file_status(fs::file_type::fifo)));
2154     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::socket)));
2155     CHECK(!fs::is_fifo(fs::file_status(fs::file_type::unknown)));
2156 }
2157 
2158 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.21 is_other", "[filesystem][operations][fs.op.is_other]")
2159 {
2160     std::error_code ec;
2161     CHECK(!fs::is_other("directory"));
2162     CHECK(!fs::is_other("regular"));
2163     if (is_symlink_creation_supported()) {
2164         CHECK(!fs::is_other("dir_symlink"));
2165         CHECK(!fs::is_other("file_symlink"));
2166     }
2167     CHECK((has_fifo() ? fs::is_other("fifo") : true));
2168     CHECK((has_socket() ? fs::is_other("socket") : true));
2169     CHECK((block_path().empty() ? true : fs::is_other(block_path())));
2170     CHECK((character_path().empty() ? true : fs::is_other(character_path())));
2171     CHECK_NOTHROW(fs::is_other("notfound"));
2172     CHECK_NOTHROW(fs::is_other("notfound", ec));
2173     CHECK(ec);
2174     ec.clear();
2175     CHECK(!fs::is_other(fs::file_status(fs::file_type::none)));
2176     CHECK(!fs::is_other(fs::file_status(fs::file_type::not_found)));
2177     CHECK(!fs::is_other(fs::file_status(fs::file_type::regular)));
2178     CHECK(!fs::is_other(fs::file_status(fs::file_type::directory)));
2179     CHECK(!fs::is_other(fs::file_status(fs::file_type::symlink)));
2180     CHECK(fs::is_other(fs::file_status(fs::file_type::block)));
2181     CHECK(fs::is_other(fs::file_status(fs::file_type::character)));
2182     CHECK(fs::is_other(fs::file_status(fs::file_type::fifo)));
2183     CHECK(fs::is_other(fs::file_status(fs::file_type::socket)));
2184     CHECK(fs::is_other(fs::file_status(fs::file_type::unknown)));
2185 }
2186 
2187 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.22 is_regular_file", "[filesystem][operations][fs.op.is_regular_file]")
2188 {
2189     std::error_code ec;
2190     CHECK(!fs::is_regular_file("directory"));
2191     CHECK(fs::is_regular_file("regular"));
2192     if (is_symlink_creation_supported()) {
2193         CHECK(!fs::is_regular_file("dir_symlink"));
2194         CHECK(fs::is_regular_file("file_symlink"));
2195     }
2196     CHECK((has_fifo() ? !fs::is_regular_file("fifo") : true));
2197     CHECK((has_socket() ? !fs::is_regular_file("socket") : true));
2198     CHECK((block_path().empty() ? true : !fs::is_regular_file(block_path())));
2199     CHECK((character_path().empty() ? true : !fs::is_regular_file(character_path())));
2200     CHECK_NOTHROW(fs::is_regular_file("notfound"));
2201     CHECK_NOTHROW(fs::is_regular_file("notfound", ec));
2202     CHECK(ec);
2203     ec.clear();
2204     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::none)));
2205     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::not_found)));
2206     CHECK(fs::is_regular_file(fs::file_status(fs::file_type::regular)));
2207     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::directory)));
2208     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::symlink)));
2209     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::block)));
2210     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::character)));
2211     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::fifo)));
2212     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::socket)));
2213     CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::unknown)));
2214 }
2215 
2216 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.23 is_socket", "[filesystem][operations][fs.op.is_socket]")
2217 {
2218     std::error_code ec;
2219     CHECK(!fs::is_socket("directory"));
2220     CHECK(!fs::is_socket("regular"));
2221     if (is_symlink_creation_supported()) {
2222         CHECK(!fs::is_socket("dir_symlink"));
2223         CHECK(!fs::is_socket("file_symlink"));
2224     }
2225     CHECK((has_fifo() ? !fs::is_socket("fifo") : true));
2226     CHECK((has_socket() ? fs::is_socket("socket") : true));
2227     CHECK((block_path().empty() ? true : !fs::is_socket(block_path())));
2228     CHECK((character_path().empty() ? true : !fs::is_socket(character_path())));
2229     CHECK_NOTHROW(fs::is_socket("notfound"));
2230     CHECK_NOTHROW(fs::is_socket("notfound", ec));
2231     CHECK(ec);
2232     ec.clear();
2233     CHECK(!fs::is_socket(fs::file_status(fs::file_type::none)));
2234     CHECK(!fs::is_socket(fs::file_status(fs::file_type::not_found)));
2235     CHECK(!fs::is_socket(fs::file_status(fs::file_type::regular)));
2236     CHECK(!fs::is_socket(fs::file_status(fs::file_type::directory)));
2237     CHECK(!fs::is_socket(fs::file_status(fs::file_type::symlink)));
2238     CHECK(!fs::is_socket(fs::file_status(fs::file_type::block)));
2239     CHECK(!fs::is_socket(fs::file_status(fs::file_type::character)));
2240     CHECK(!fs::is_socket(fs::file_status(fs::file_type::fifo)));
2241     CHECK(fs::is_socket(fs::file_status(fs::file_type::socket)));
2242     CHECK(!fs::is_socket(fs::file_status(fs::file_type::unknown)));
2243 }
2244 
2245 TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.24 is_symlink", "[filesystem][operations][fs.op.is_symlink]")
2246 {
2247     std::error_code ec;
2248     CHECK(!fs::is_symlink("directory"));
2249     CHECK(!fs::is_symlink("regular"));
2250     if (is_symlink_creation_supported()) {
2251         CHECK(fs::is_symlink("dir_symlink"));
2252         CHECK(fs::is_symlink("file_symlink"));
2253     }
2254     CHECK((has_fifo() ? !fs::is_symlink("fifo") : true));
2255     CHECK((has_socket() ? !fs::is_symlink("socket") : true));
2256     CHECK((block_path().empty() ? true : !fs::is_symlink(block_path())));
2257     CHECK((character_path().empty() ? true : !fs::is_symlink(character_path())));
2258     CHECK_NOTHROW(fs::is_symlink("notfound"));
2259     CHECK_NOTHROW(fs::is_symlink("notfound", ec));
2260     CHECK(ec);
2261     ec.clear();
2262     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::none)));
2263     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::not_found)));
2264     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::regular)));
2265     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::directory)));
2266     CHECK(fs::is_symlink(fs::file_status(fs::file_type::symlink)));
2267     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::block)));
2268     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::character)));
2269     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::fifo)));
2270     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::socket)));
2271     CHECK(!fs::is_symlink(fs::file_status(fs::file_type::unknown)));
2272 }
2273 
timeFromString(const std::string & str)2274 static fs::file_time_type timeFromString(const std::string& str)
2275 {
2276     struct ::tm tm;
2277     ::memset(&tm, 0, sizeof(::tm));
2278     std::istringstream is(str);
2279     is >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
2280     if (is.fail()) {
2281         throw std::exception();
2282     }
2283     return from_time_t<fs::file_time_type>(std::mktime(&tm));
2284 }
2285 
2286 TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_write_time]")
2287 {
2288     TemporaryDirectory t(TempOpt::change_path);
2289     std::error_code ec;
2290     fs::file_time_type ft;
2291     generateFile("foo");
2292     auto now = fs::file_time_type::clock::now();
2293     CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time(t.path()) - now).count()) < 3);
2294     CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - now).count()) < 3);
2295     CHECK_THROWS_AS(fs::last_write_time("bar"), fs::filesystem_error);
2296     CHECK_NOTHROW(ft = fs::last_write_time("bar", ec));
2297     CHECK(ft == fs::file_time_type::min());
2298     CHECK(ec);
2299     ec.clear();
2300     if (is_symlink_creation_supported()) {
2301         std::this_thread::sleep_for(std::chrono::seconds(1));
2302         fs::create_symlink("foo", "foo2");
2303         ft = fs::last_write_time("foo");
2304         // checks that the time of the symlink is fetched
2305         CHECK(ft == fs::last_write_time("foo2"));
2306     }
2307     auto nt = timeFromString("2015-10-21T04:30:00");
2308     CHECK_NOTHROW(fs::last_write_time(t.path() / "foo", nt));
2309     CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
2310     nt = timeFromString("2015-10-21T04:29:00");
2311     CHECK_NOTHROW(fs::last_write_time("foo", nt, ec));
2312     CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
2313     CHECK(!ec);
2314     CHECK_THROWS_AS(fs::last_write_time("bar", nt), fs::filesystem_error);
2315     CHECK_NOTHROW(fs::last_write_time("bar", nt, ec));
2316     CHECK(ec);
2317 }
2318 
2319 TEST_CASE("30.10.15.26 permissions", "[filesystem][operations][fs.op.permissions]")
2320 {
2321     TemporaryDirectory t(TempOpt::change_path);
2322     std::error_code ec;
2323     generateFile("foo", 512);
2324     auto allWrite = fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write;
2325     CHECK_NOTHROW(fs::permissions("foo", allWrite, fs::perm_options::remove));
2326     CHECK((fs::status("foo").permissions() & fs::perms::owner_write) != fs::perms::owner_write);
2327     CHECK_THROWS_AS(fs::resize_file("foo", 1024), fs::filesystem_error);
2328     CHECK(fs::file_size("foo") == 512);
2329     CHECK_NOTHROW(fs::permissions("foo", fs::perms::owner_write, fs::perm_options::add));
2330     CHECK((fs::status("foo").permissions() & fs::perms::owner_write) == fs::perms::owner_write);
2331     CHECK_NOTHROW(fs::resize_file("foo", 2048));
2332     CHECK(fs::file_size("foo") == 2048);
2333     CHECK_THROWS_AS(fs::permissions("bar", fs::perms::owner_write, fs::perm_options::add), fs::filesystem_error);
2334     CHECK_NOTHROW(fs::permissions("bar", fs::perms::owner_write, fs::perm_options::add, ec));
2335     CHECK(ec);
2336     CHECK_THROWS_AS(fs::permissions("bar", fs::perms::owner_write, static_cast<fs::perm_options>(0)), fs::filesystem_error);
2337 }
2338 
2339 TEST_CASE("30.10.15.27 proximate", "[filesystem][operations][fs.op.proximate]")
2340 {
2341     std::error_code ec;
2342     CHECK(fs::proximate("/a/d", "/a/b/c") == "../../d");
2343     CHECK(fs::proximate("/a/d", "/a/b/c", ec) == "../../d");
2344     CHECK(!ec);
2345     CHECK(fs::proximate("/a/b/c", "/a/d") == "../b/c");
2346     CHECK(fs::proximate("/a/b/c", "/a/d", ec) == "../b/c");
2347     CHECK(!ec);
2348     CHECK(fs::proximate("a/b/c", "a") == "b/c");
2349     CHECK(fs::proximate("a/b/c", "a", ec) == "b/c");
2350     CHECK(!ec);
2351     CHECK(fs::proximate("a/b/c", "a/b/c/x/y") == "../..");
2352     CHECK(fs::proximate("a/b/c", "a/b/c/x/y", ec) == "../..");
2353     CHECK(!ec);
2354     CHECK(fs::proximate("a/b/c", "a/b/c") == ".");
2355     CHECK(fs::proximate("a/b/c", "a/b/c", ec) == ".");
2356     CHECK(!ec);
2357     CHECK(fs::proximate("a/b", "c/d") == "../../a/b");
2358     CHECK(fs::proximate("a/b", "c/d", ec) == "../../a/b");
2359     CHECK(!ec);
2360 #ifndef GHC_OS_WINDOWS
2361     if (has_host_root_name_support()) {
2362         CHECK(fs::proximate("//host1/a/d", "//host2/a/b/c") == "//host1/a/d");
2363         CHECK(fs::proximate("//host1/a/d", "//host2/a/b/c", ec) == "//host1/a/d");
2364         CHECK(!ec);
2365     }
2366 #endif
2367 }
2368 
2369 TEST_CASE("30.10.15.28 read_symlink", "[filesystem][operations][fs.op.read_symlink]")
2370 {
2371     if (is_symlink_creation_supported()) {
2372         TemporaryDirectory t(TempOpt::change_path);
2373         std::error_code ec;
2374         generateFile("foo");
2375         fs::create_symlink(t.path() / "foo", "bar");
2376         CHECK(fs::read_symlink("bar") == t.path() / "foo");
2377         CHECK(fs::read_symlink("bar", ec) == t.path() / "foo");
2378         CHECK(!ec);
2379         CHECK_THROWS_AS(fs::read_symlink("foobar"), fs::filesystem_error);
2380         CHECK(fs::read_symlink("foobar", ec) == fs::path());
2381         CHECK(ec);
2382     }
2383 }
2384 
2385 TEST_CASE("30.10.15.29 relative", "[filesystem][operations][fs.op.relative]")
2386 {
2387     CHECK(fs::relative("/a/d", "/a/b/c") == "../../d");
2388     CHECK(fs::relative("/a/b/c", "/a/d") == "../b/c");
2389     CHECK(fs::relative("a/b/c", "a") == "b/c");
2390     CHECK(fs::relative("a/b/c", "a/b/c/x/y") == "../..");
2391     CHECK(fs::relative("a/b/c", "a/b/c") == ".");
2392     CHECK(fs::relative("a/b", "c/d") == "../../a/b");
2393     std::error_code ec;
2394     CHECK(fs::relative(fs::current_path() / "foo", ec) == "foo");
2395     CHECK(!ec);
2396 }
2397 
2398 TEST_CASE("30.10.15.30 remove", "[filesystem][operations][fs.op.remove]")
2399 {
2400     TemporaryDirectory t(TempOpt::change_path);
2401     std::error_code ec;
2402     generateFile("foo");
2403     CHECK(fs::remove("foo"));
2404     CHECK(!fs::exists("foo"));
2405     CHECK(!fs::remove("foo"));
2406     generateFile("foo");
2407     CHECK(fs::remove("foo", ec));
2408     CHECK(!fs::exists("foo"));
2409     if (is_symlink_creation_supported()) {
2410         generateFile("foo");
2411         fs::create_symlink("foo", "bar");
2412         CHECK(fs::exists(fs::symlink_status("bar")));
2413         CHECK(fs::remove("bar", ec));
2414         CHECK(fs::exists("foo"));
2415         CHECK(!fs::exists(fs::symlink_status("bar")));
2416     }
2417     CHECK(!fs::remove("bar"));
2418     CHECK(!fs::remove("bar", ec));
2419     CHECK(!ec);
2420 }
2421 
2422 TEST_CASE("30.10.15.31 remove_all", "[filesystem][operations][fs.op.remove_all]")
2423 {
2424     TemporaryDirectory t(TempOpt::change_path);
2425     std::error_code ec;
2426     generateFile("foo");
2427     CHECK(fs::remove_all("foo", ec) == 1);
2428     CHECK(!ec);
2429     ec.clear();
2430     CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
2431     fs::create_directories("dir1/dir1a");
2432     fs::create_directories("dir1/dir1b");
2433     generateFile("dir1/dir1a/f1");
2434     generateFile("dir1/dir1b/f2");
2435     CHECK_NOTHROW(fs::remove_all("dir1/non-existing", ec));
2436     CHECK(!ec);
2437     CHECK(fs::remove_all("dir1/non-existing", ec) == 0);
2438     CHECK(fs::remove_all("dir1") == 5);
2439     CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator());
2440 }
2441 
2442 TEST_CASE("30.10.15.32 rename", "[filesystem][operations][fs.op.rename]")
2443 {
2444     TemporaryDirectory t(TempOpt::change_path);
2445     std::error_code ec;
2446     generateFile("foo", 123);
2447     fs::create_directory("dir1");
2448     CHECK_NOTHROW(fs::rename("foo", "bar"));
2449     CHECK(!fs::exists("foo"));
2450     CHECK(fs::exists("bar"));
2451     CHECK_NOTHROW(fs::rename("dir1", "dir2"));
2452     CHECK(fs::exists("dir2"));
2453     generateFile("foo2", 42);
2454     CHECK_NOTHROW(fs::rename("bar", "foo2"));
2455     CHECK(fs::exists("foo2"));
2456     CHECK(fs::file_size("foo2") == 123u);
2457     CHECK(!fs::exists("bar"));
2458     CHECK_NOTHROW(fs::rename("foo2", "foo", ec));
2459     CHECK(!ec);
2460     CHECK_THROWS_AS(fs::rename("foobar", "barfoo"), fs::filesystem_error);
2461     CHECK_NOTHROW(fs::rename("foobar", "barfoo", ec));
2462     CHECK(ec);
2463     CHECK(!fs::exists("barfoo"));
2464 }
2465 
2466 TEST_CASE("30.10.15.33 resize_file", "[filesystem][operations][fs.op.resize_file]")
2467 {
2468     TemporaryDirectory t(TempOpt::change_path);
2469     std::error_code ec;
2470     generateFile("foo", 1024);
2471     CHECK(fs::file_size("foo") == 1024);
2472     CHECK_NOTHROW(fs::resize_file("foo", 2048));
2473     CHECK(fs::file_size("foo") == 2048);
2474     CHECK_NOTHROW(fs::resize_file("foo", 1000, ec));
2475     CHECK(!ec);
2476     CHECK(fs::file_size("foo") == 1000);
2477     CHECK_THROWS_AS(fs::resize_file("bar", 2048), fs::filesystem_error);
2478     CHECK(!fs::exists("bar"));
2479     CHECK_NOTHROW(fs::resize_file("bar", 4096, ec));
2480     CHECK(ec);
2481     CHECK(!fs::exists("bar"));
2482 }
2483 
2484 TEST_CASE("30.10.15.34 space", "[filesystem][operations][fs.op.space]")
2485 {
2486     {
2487         fs::space_info si;
2488         CHECK_NOTHROW(si = fs::space(fs::current_path()));
2489         CHECK(si.capacity > 1024 * 1024);
2490         CHECK(si.capacity > si.free);
2491         CHECK(si.free >= si.available);
2492     }
2493     {
2494         std::error_code ec;
2495         fs::space_info si;
2496         CHECK_NOTHROW(si = fs::space(fs::current_path(), ec));
2497         CHECK(si.capacity > 1024 * 1024);
2498         CHECK(si.capacity > si.free);
2499         CHECK(si.free >= si.available);
2500         CHECK(!ec);
2501     }
2502     {
2503         std::error_code ec;
2504         fs::space_info si;
2505         CHECK_NOTHROW(si = fs::space("foobar42", ec));
2506         CHECK(si.capacity == static_cast<uintmax_t>(-1));
2507         CHECK(si.free == static_cast<uintmax_t>(-1));
2508         CHECK(si.available == static_cast<uintmax_t>(-1));
2509         CHECK(ec);
2510     }
2511     CHECK_THROWS_AS(fs::space("foobar42"), fs::filesystem_error);
2512 }
2513 
2514 TEST_CASE("30.10.15.35 status", "[filesystem][operations][fs.op.status]")
2515 {
2516     TemporaryDirectory t(TempOpt::change_path);
2517     std::error_code ec;
2518     fs::file_status fs;
2519     CHECK_NOTHROW(fs = fs::status("foo"));
2520     CHECK(fs.type() == fs::file_type::not_found);
2521     CHECK(fs.permissions() == fs::perms::unknown);
2522     CHECK_NOTHROW(fs = fs::status("bar", ec));
2523     CHECK(fs.type() == fs::file_type::not_found);
2524     CHECK(fs.permissions() == fs::perms::unknown);
2525     CHECK(ec);
2526     ec.clear();
2527     fs = fs::status(t.path());
2528     CHECK(fs.type() == fs::file_type::directory);
2529     CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
2530     generateFile("foobar");
2531     fs = fs::status(t.path() / "foobar");
2532     CHECK(fs.type() == fs::file_type::regular);
2533     CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
2534     if (is_symlink_creation_supported()) {
2535         fs::create_symlink(t.path() / "foobar", t.path() / "barfoo");
2536         fs = fs::status(t.path() / "barfoo");
2537         CHECK(fs.type() == fs::file_type::regular);
2538         CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
2539     }
2540 }
2541 
2542 TEST_CASE("30.10.15.36 status_known", "[filesystem][operations][fs.op.status_known]")
2543 {
2544     CHECK(!fs::status_known(fs::file_status()));
2545     CHECK(fs::status_known(fs::file_status(fs::file_type::not_found)));
2546     CHECK(fs::status_known(fs::file_status(fs::file_type::regular)));
2547     CHECK(fs::status_known(fs::file_status(fs::file_type::directory)));
2548     CHECK(fs::status_known(fs::file_status(fs::file_type::symlink)));
2549     CHECK(fs::status_known(fs::file_status(fs::file_type::character)));
2550     CHECK(fs::status_known(fs::file_status(fs::file_type::fifo)));
2551     CHECK(fs::status_known(fs::file_status(fs::file_type::socket)));
2552     CHECK(fs::status_known(fs::file_status(fs::file_type::unknown)));
2553 }
2554 
2555 TEST_CASE("30.10.15.37 symlink_status", "[filesystem][operations][fs.op.symlink_status]")
2556 {
2557     TemporaryDirectory t(TempOpt::change_path);
2558     std::error_code ec;
2559     fs::file_status fs;
2560     CHECK_NOTHROW(fs = fs::symlink_status("foo"));
2561     CHECK(fs.type() == fs::file_type::not_found);
2562     CHECK(fs.permissions() == fs::perms::unknown);
2563     CHECK_NOTHROW(fs = fs::symlink_status("bar", ec));
2564     CHECK(fs.type() == fs::file_type::not_found);
2565     CHECK(fs.permissions() == fs::perms::unknown);
2566     CHECK(ec);
2567     ec.clear();
2568     fs = fs::symlink_status(t.path());
2569     CHECK(fs.type() == fs::file_type::directory);
2570     CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
2571     generateFile("foobar");
2572     fs = fs::symlink_status(t.path() / "foobar");
2573     CHECK(fs.type() == fs::file_type::regular);
2574     CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write));
2575     if (is_symlink_creation_supported()) {
2576         fs::create_symlink(t.path() / "foobar", t.path() / "barfoo");
2577         fs = fs::symlink_status(t.path() / "barfoo");
2578         CHECK(fs.type() == fs::file_type::symlink);
2579     }
2580 }
2581 
2582 TEST_CASE("30.10.15.38 temporary_directory_path", "[filesystem][operations][fs.op.temp_dir_path]")
2583 {
2584     std::error_code ec;
2585     CHECK_NOTHROW(fs::exists(fs::temp_directory_path()));
2586     CHECK_NOTHROW(fs::exists(fs::temp_directory_path(ec)));
2587     CHECK(!fs::temp_directory_path().empty());
2588     CHECK(!ec);
2589 }
2590 
2591 TEST_CASE("30.10.15.39 weakly_canonical", "[filesystem][operations][fs.op.weakly_canonical]")
2592 {
2593     INFO("This might fail on std::implementations that return fs::current_path() for fs::canonical(\"\")");
2594     CHECK(fs::weakly_canonical("") == ".");
2595     if(fs::weakly_canonical("") == ".") {
2596         CHECK(fs::weakly_canonical("foo/bar") == "foo/bar");
2597         CHECK(fs::weakly_canonical("foo/./bar") == "foo/bar");
2598         CHECK(fs::weakly_canonical("foo/../bar") == "bar");
2599     }
2600     else {
2601         CHECK(fs::weakly_canonical("foo/bar") == fs::current_path() / "foo/bar");
2602         CHECK(fs::weakly_canonical("foo/./bar") == fs::current_path() / "foo/bar");
2603         CHECK(fs::weakly_canonical("foo/../bar") == fs::current_path() / "bar");
2604     }
2605 
2606     {
2607         TemporaryDirectory t(TempOpt::change_path);
2608         auto dir = t.path() / "d0";
2609         fs::create_directories(dir / "d1");
2610         generateFile(dir / "f0");
2611         fs::path rel(dir.filename());
2612         CHECK(fs::weakly_canonical(dir) == dir);
2613         CHECK(fs::weakly_canonical(rel) == dir);
2614         CHECK(fs::weakly_canonical(dir / "f0") == dir / "f0");
2615         CHECK(fs::weakly_canonical(dir / "f0/") == dir / "f0/");
2616         CHECK(fs::weakly_canonical(dir / "f1") == dir / "f1");
2617         CHECK(fs::weakly_canonical(rel / "f0") == dir / "f0");
2618         CHECK(fs::weakly_canonical(rel / "f0/") == dir / "f0/");
2619         CHECK(fs::weakly_canonical(rel / "f1") == dir / "f1");
2620         CHECK(fs::weakly_canonical(rel / "./f0") == dir / "f0");
2621         CHECK(fs::weakly_canonical(rel / "./f1") == dir / "f1");
2622         CHECK(fs::weakly_canonical(rel / "d1/../f0") == dir / "f0");
2623         CHECK(fs::weakly_canonical(rel / "d1/../f1") == dir / "f1");
2624         CHECK(fs::weakly_canonical(rel / "d1/../f1/../f2") == dir / "f2");
2625     }
2626 }
2627 
2628 TEST_CASE("std::string_view support", "[filesystem][fs.string_view]")
2629 {
2630 #if __cpp_lib_string_view
2631     std::string p("foo/bar");
2632     std::string_view sv(p);
2633     CHECK(fs::path(sv, fs::path::format::generic_format).generic_string() == "foo/bar");
2634     fs::path p2("fo");
2635     p2 += std::string_view("o");
2636     CHECK(p2 == "foo");
2637     CHECK(p2.compare(std::string_view("foo")) == 0);
2638 #else
2639     WARN("std::string_view specific tests are empty without std::string_view.");
2640 #endif
2641 }
2642 
2643 TEST_CASE("Windows: Long filename support", "[filesystem][path][fs.path.win.long]")
2644 {
2645 #ifdef GHC_OS_WINDOWS
2646     TemporaryDirectory t(TempOpt::change_path);
2647     char c = 'A';
2648     fs::path dir = "\\\\?\\" + fs::current_path().u8string();
2649     for (; c <= 'Z'; ++c) {
2650         std::string part = std::string(16, c);
2651         dir /= part;
2652         CHECK_NOTHROW(fs::create_directory(dir));
2653         CHECK(fs::exists(dir));
2654         generateFile(dir / "f0");
2655         CHECK(fs::exists(dir / "f0"));
2656         std::string native = dir.u8string();
2657         if (native.substr(0, 4) == "\\\\?\\") {
2658             break;
2659         }
2660     }
2661     CHECK(c <= 'Z');
2662 #else
2663     WARN("Windows specific tests are empty on non-Windows systems.");
2664 #endif
2665 }
2666 
2667 TEST_CASE("Windows: UNC path support", "[filesystem][path][fs.path.win.unc]")
2668 {
2669 #ifdef GHC_OS_WINDOWS
2670     std::error_code ec;
2671     fs::path p(R"(\\localhost\c$\Windows)");
2672     auto symstat = fs::symlink_status(p, ec);
2673     CHECK(!ec);
2674     auto p2 = fs::canonical(p, ec);
2675     CHECK(!ec);
2676     CHECK(p2 == p);
2677 
2678     std::vector<fs::path> variants = {
2679         R"(C:\Windows\notepad.exe)",
2680         R"(\\.\C:\Windows\notepad.exe)",
2681         R"(\\?\C:\Windows\notepad.exe)",
2682         R"(\??\C:\Windows\notepad.exe)",
2683         R"(\\?\HarddiskVolume1\Windows\notepad.exe)",
2684         R"(\\?\Harddisk0Partition1\Windows\notepad.exe)",
2685         R"(\\.\GLOBALROOT\Device\HarddiskVolume1\Windows\notepad.exe)",
2686         R"(\\?\GLOBALROOT\Device\Harddisk0\Partition1\Windows\notepad.exe)",
2687         R"(\\?\Volume{e8a4a89d-0000-0000-0000-100000000000}\Windows\notepad.exe)",
2688         R"(\\LOCALHOST\C$\Windows\notepad.exe)",
2689         R"(\\?\UNC\C$\Windows\notepad.exe)",
2690         R"(\\?\GLOBALROOT\Device\Mup\C$\Windows\notepad.exe)",
2691     };
2692     for (auto pt : variants) {
2693         std::cerr << pt.string() << " - " << pt.root_name() << ", " << pt.root_path() << ": " << iterateResult(pt) << std::endl;
2694     }
2695 #else
2696     WARN("Windows specific tests are empty on non-Windows systems.");
2697 #endif
2698 }
2699