From dc37276a9af1e0d0f9d1f739423c753c73ea7ed3 Mon Sep 17 00:00:00 2001 From: Steffen Schuemann Date: Sun, 5 May 2019 08:51:53 +0200 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8d9f245e379d373942c0f49be19dacc9293cdcf0 Merge: 3ceb4b0 857a355 Author: gulrak Date: Fri May 3 23:52:57 2019 +0200 Merge branch 'development-v1.1' of https://github.com/gulrak/filesystem into development-v1.1 commit 3ceb4b0e4fe90be46b1fdbdfb7e2b3f160cccf3c Author: gulrak Date: Fri May 3 23:51:48 2019 +0200 Less noisy interoperability testing on weakly_canonial() commit 38f82a90ef5f4ec1fa341ce3ab34f3836a6bd9ea Author: gulrak Date: Fri May 3 23:50:43 2019 +0200 Additional fix for recursive_directory_iterator commit 857a3558fb13e8fae76e29b5b91cb76b5e98ea20 Merge: 9da5784 b557b5b Author: Steffen Schuemann Date: Fri May 3 23:47:20 2019 +0200 Merge branch 'development-v1.1' of github.com:gulrak/filesystem into development-v1.1 # Conflicts: # test/filesystem_test.cpp commit 9da57846ac4de06c4b0521ab69ea42816fd6a029 Merge: 96e89ae 43e75c3 Author: Steffen Schuemann Date: Fri May 3 23:42:31 2019 +0200 Merge remote-tracking branch 'origin/master' into development-v1.1 commit 96e89ae7f9e983cb3d0977d9ba77f421a0c06b0f Merge: 9d71161 882c60b Author: Steffen Schuemann Date: Fri May 3 23:40:18 2019 +0200 Merge remote-tracking branch 'origin/master' into development-v1.1 commit b557b5b476c085183bd3da72cc9f511df3b52272 Merge: 263a2d2 9d71161 Author: Steffen Schümann Date: Fri May 3 22:44:25 2019 +0200 Merge branch 'development-v1.1' of https://github.com/gulrak/filesystem into development-v1.1 commit 263a2d2c5b9f25631513271a6e26a9cb66e8f9da Author: Steffen Schümann Date: Fri May 3 22:44:01 2019 +0200 Work on Windows tests. commit 9d71161323f22e994b51fda73ebc19af9e67d6e6 Author: Steffen Schuemann Date: Fri May 3 08:30:40 2019 +0200 Fix for issues with recursive_directory_iterator not behaving like an input iterator and regarding pop()/depth(). commit 2ac1352b4a37fdb247b56fb63c1e2c3f56761649 Author: gulrak Date: Thu May 2 09:12:42 2019 +0200 Refactored builds with std::fs to a CMake macro, added du example, added behaviour switch commit 624a6f63e5639504c2b554ba89985ef9c01c6fa9 Author: Steffen Schümann Date: Thu May 2 09:01:15 2019 +0200 Add path parameters to filesystem_error::what --- .gitignore | 1 + CMakeLists.txt | 9 ++++-- README.md | 15 ++++++++-- cmake/GhcHelper.cmake | 36 +++++++++++++++++++++++ examples/CMakeLists.txt | 33 +++------------------ examples/du.cpp | 57 ++++++++++++++++++++++++++++++++++++ include/ghc/filesystem.hpp | 59 +++++++++++++++++++++++++++++--------- test/CMakeLists.txt | 29 +------------------ test/filesystem_test.cpp | 49 ++++++++++++++++++++++++------- 9 files changed, 201 insertions(+), 87 deletions(-) create mode 100644 cmake/GhcHelper.cmake create mode 100644 examples/du.cpp diff --git a/.gitignore b/.gitignore index a0155cb..d787f76 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /build*/ +.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 597675c..39e3d85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,10 @@ target_compile_options(ghc_filesystem INTERFACE "$<$:/utf- get_directory_property(hasParent PARENT_DIRECTORY) if(NOT hasParent) - enable_testing() - add_subdirectory(test) - add_subdirectory(examples) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + include(GhcHelper) + enable_testing() + add_subdirectory(test) + add_subdirectory(examples) endif() diff --git a/README.md b/README.md index 5ba6b78..bda1923 100644 --- a/README.md +++ b/README.md @@ -402,9 +402,8 @@ But this makes `fs::copy` with `fs::copy_options::create_symlinks` or `fs::copy_ just a more complicated syntax for the `fs::create_symlink` or `fs::create_hardlink` operation and I don't want to believe, that this was the intention of the original writing. As there is another issue related to copy, with a different take on the description, -I keep my version the way I read the description, as it is not contradicting the standard and useful. Let's see -what final solution the LWG comes up with in the end. - +*Note:* With v1.1.2 I decided to integrate a behavior switch for this and make the LWG #2682 +the default. ## Open Issues @@ -446,6 +445,16 @@ to the expected behavior. `fs::recursive_directory_iterator` could run into endless loops, the methods depth() and pop() had issues and the copy behaviour and `input_iterator_tag` conformance was broken, added tests +* Restructured some CMake code into a macro to ease the support for + C++17 std::filesystem builds of tests and examples for interoperability + checks. +* Some fixes on Windows tests to ease interoperability test runs. +* Reduced noise on `fs::weakly_canonical()` tests against `std::fs` +* Added simple `du` example showing the `recursive_directory_iterator` + used to add the sizes of files in a directory tree. +* Added error checking in `fs::file_time_type` test helpers +* `fs::copy()` now conforms LWG #2682, disallowing the use of + `copy_option::create_symlinks' to be used on directories ### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0) diff --git a/cmake/GhcHelper.cmake b/cmake/GhcHelper.cmake new file mode 100644 index 0000000..b095d2e --- /dev/null +++ b/cmake/GhcHelper.cmake @@ -0,0 +1,36 @@ +macro(AddExecutableWithStdFS targetName) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)) + if(APPLE) + include_directories(/usr/local/opt/llvm/include) + link_directories(/usr/local/opt/llvm/lib) + endif() + add_executable(${targetName} ${ARGN}) + set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17) + if(APPLE) + target_link_libraries(${targetName} -lc++fs) + else() + target_compile_options(${targetName} PRIVATE "-stdlib=libc++") + target_link_libraries(${targetName} -stdlib=libc++ -lc++fs) + endif() + + target_link_libraries(${targetName} -lc++fs) + target_compile_definitions(${targetName} PRIVATE USE_STD_FS) +endif() + +if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)) + add_executable(${targetName} ${ARGN}) + set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17) + target_link_libraries(${targetName} -lstdc++fs) + target_compile_definitions(${targetName} PRIVATE USE_STD_FS) +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15)) + add_executable(${targetName} ${ARGN}) + set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17) + set_property(TARGET ${targetName} PROPERTY CXX_STANDARD_REQUIRED ON) + target_compile_options(${targetName} PRIVATE "/Zc:__cplusplus") + target_compile_definitions(${targetName} PRIVATE USE_STD_FS _CRT_SECURE_NO_WARNINGS) +endif() + +endmacro() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 817200b..90a303f 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,34 +4,9 @@ target_link_libraries(fs_dir ghc_filesystem) if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) target_compile_definitions(fs_dir PRIVATE _CRT_SECURE_NO_WARNINGS) endif() +AddExecutableWithStdFS(std_fs_dir dir.cpp) -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)) - if(APPLE) - include_directories(/usr/local/opt/llvm/include) - link_directories(/usr/local/opt/llvm/lib) - endif() - add_executable(std_fs_dir dir.cpp) - set_property(TARGET std_fs_dir PROPERTY CXX_STANDARD 17) - if(APPLE) - target_link_libraries(std_fs_dir -lc++fs) - else() - target_compile_options(std_fs_dir PRIVATE "-stdlib=libc++") - target_link_libraries(std_fs_dir -stdlib=libc++ -lc++fs) - endif() +add_executable(fs_du du.cpp) +target_link_libraries(fs_du ghc_filesystem) +AddExecutableWithStdFS(std_fs_du du.cpp) - target_link_libraries(std_fs_dir -lc++fs) -endif() - -if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)) - add_executable(std_fs_dir dir.cpp) - set_property(TARGET std_fs_dir PROPERTY CXX_STANDARD 17) - target_link_libraries(std_fs_dir -lstdc++fs) -endif() - -if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15)) - add_executable(std_fs_dir dir.cpp) - set_property(TARGET std_fs_dir PROPERTY CXX_STANDARD 17) - set_property(TARGET std_fs_dir PROPERTY CXX_STANDARD_REQUIRED ON) - target_compile_options(std_fs_dir PRIVATE "/Zc:__cplusplus") - target_compile_definitions(std_fs_dir PRIVATE _CRT_SECURE_NO_WARNINGS) -endif() diff --git a/examples/du.cpp b/examples/du.cpp new file mode 100644 index 0000000..88436d9 --- /dev/null +++ b/examples/du.cpp @@ -0,0 +1,57 @@ +#include +#include +#include + +#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) && __has_include() +#include +namespace fs = std::filesystem; +#else +#include +namespace fs = ghc::filesystem; +#endif + +int main(int argc, char* argv[]) +{ +#ifdef GHC_FILESYSTEM_VERSION + fs::u8arguments u8guard(argc, argv); + if(!u8guard.valid()) { + std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl; + std::exit(EXIT_FAILURE); + } +#endif + if(argc > 2) { + std::cerr << "USAGE: du " << std::endl; + exit(1); + } + fs::path dir{"."}; + if(argc == 2) { + dir = fs::u8path(argv[1]); + } + + uint64_t totalSize = 0; + int totalDirs = 0; + int totalFiles = 0; + int maxDepth = 0; + + try { + auto rdi = fs::recursive_directory_iterator(dir); + for(auto de : rdi) { + if(rdi.depth() > maxDepth) { + maxDepth = rdi.depth(); + } + if(de.is_regular_file()) { + totalSize += de.file_size(); + ++totalFiles; + } + else if(de.is_directory()) { + ++totalDirs; + } + } + } + catch(fs::filesystem_error fe) { + std::cerr << "Error: " << fe.what() << std::endl; + exit(1); + } + std::cout << totalSize << " bytes in " << totalFiles << " and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl; + return 0; +} diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index b1d5bd9..3657df7 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -92,6 +92,7 @@ #ifdef GHC_OS_WINDOWS #include +// additional includes #include #include #include @@ -142,9 +143,20 @@ #include #endif // GHC_EXPAND_IMPL -// configure LWG conformance (see README.md) +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories +// configure LWG conformance () +#define LWG_2682_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular +// file with that name, it is superceded by P1164R1, so only activate if really needed // #define LWG_2935_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) #define LWG_2937_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) #define GHC_FILESYSTEM_VERSION 10101L @@ -1014,6 +1026,7 @@ enum class portable_error { not_supported, not_implemented, invalid_argument, + is_a_directory, }; GHC_FS_API std::error_code make_error_code(portable_error err); } // namespace detail @@ -1038,6 +1051,8 @@ GHC_INLINE std::error_code make_error_code(portable_error err) return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category()); case portable_error::invalid_argument: return std::error_code(ERROR_INVALID_PARAMETER, std::system_category()); + case portable_error::is_a_directory: + return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); } #else switch (err) { @@ -1053,6 +1068,8 @@ GHC_INLINE std::error_code make_error_code(portable_error err) return std::error_code(ENOSYS, std::system_category()); case portable_error::invalid_argument: return std::error_code(EINVAL, std::system_category()); + case portable_error::is_a_directory: + return std::error_code(EISDIR, std::system_category()); } #endif return std::error_code(); @@ -1648,9 +1665,9 @@ GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::er GHC_INLINE bool is_not_found_error(std::error_code& ec) { #ifdef GHC_OS_WINDOWS - return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND; + return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME; #else - return ec.value() == ENOENT; + return ec.value() == ENOENT || ec.value() == ENOTDIR; #endif } @@ -1672,7 +1689,7 @@ GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uin fs.type(file_type::symlink); } } - if (ec.value() == ERROR_FILE_NOT_FOUND) { + if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found); } return ec ? file_status(file_type::none) : fs; @@ -1687,9 +1704,8 @@ GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uin file_status f_s = detail::file_status_from_st_mode(fs.st_mode); return f_s; } - auto error = errno; - ec = std::error_code(error, std::system_category()); - if (error == ENOENT) { + ec = std::error_code(errno, std::system_category()); + if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); @@ -1757,9 +1773,8 @@ GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status return fs; } else { - auto error = errno; ec = std::error_code(errno, std::system_category()); - if (error == ENOENT) { + if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); @@ -1800,6 +1815,7 @@ GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv) #endif } + //----------------------------------------------------------------------------- // 30.10.8.4.1 constructors and destructor @@ -2741,6 +2757,9 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const , _ec(ec) , _p1(p1) { + if (!_p1.empty()) { + _what_arg += ": '" + _p1.u8string() + "'"; + } } GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec) @@ -2750,6 +2769,12 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const , _p1(p1) , _p2(p2) { + if (!_p1.empty()) { + _what_arg += ": '" + _p1.u8string() + "'"; + } + if (!_p2.empty()) { + _what_arg += ", '" + _p2.u8string() + "'"; + } } GHC_INLINE const path& filesystem_error::path1() const noexcept @@ -2868,7 +2893,7 @@ GHC_INLINE path canonical(const path& p, std::error_code& ec) result = result.parent_path(); continue; } - else if ((result/pe).string().length() <= root.string().length()) { + else if ((result / pe).string().length() <= root.string().length()) { result /= pe; continue; } @@ -2958,10 +2983,10 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options, std } else if (is_regular_file(fs_from)) { if ((options & copy_options::directories_only) == copy_options::none) { - if ((options & copy_options::create_symlinks) == copy_options::create_symlinks) { + if ((options & copy_options::create_symlinks) != copy_options::none) { create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec); } - else if ((options & copy_options::create_hard_links) == copy_options::create_hard_links) { + else if ((options & copy_options::create_hard_links) != copy_options::none) { create_hard_link(from, to, ec); } else if (is_directory(fs_to)) { @@ -2972,7 +2997,12 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options, std } } } - else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) == copy_options::recursive)) { +#ifdef LWG_2682_BEHAVIOUR + else if(is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { + ec = detail::make_error_code(detail::portable_error::is_a_directory); + } +#endif + else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) { if (!exists(fs_to)) { create_directory(to, from, ec); if (ec) { @@ -4077,7 +4107,8 @@ GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept bool scan = true; for (auto pe : p) { if (scan) { - if (exists(result / pe, ec)) { + std::error_code tec; + if (exists(result / pe, tec)) { result /= pe; } else { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 96268dd..bdc182c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,34 +18,7 @@ if(CMAKE_GENERATOR STREQUAL Xcode) target_link_libraries(filesystem_test_cov PUBLIC ghc_filesystem PRIVATE --coverage) endif() ParseAndAddCatchTests(filesystem_test filesystem_test) - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)) - if(APPLE) - include_directories(/usr/local/opt/llvm/include) - link_directories(/usr/local/opt/llvm/lib) - endif() - add_executable(std_filesystem_test filesystem_test.cpp catch.hpp) - set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) - target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) - if(APPLE) - target_link_libraries(std_filesystem_test -lc++fs) - else() - target_compile_options(std_filesystem_test PRIVATE "-stdlib=libc++") - target_link_libraries(std_filesystem_test -stdlib=libc++ -lc++fs) - endif() -endif() -if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)) - add_executable(std_filesystem_test filesystem_test.cpp catch.hpp) - set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) - target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) - target_link_libraries(std_filesystem_test -lstdc++fs) -endif() -if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15)) - add_executable(std_filesystem_test filesystem_test.cpp catch.hpp) - set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) - target_compile_options(std_filesystem_test PRIVATE "/Zc:__cplusplus") - target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS _CRT_SECURE_NO_WARNINGS) -endif() +AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp) add_executable(multifile_test multi1.cpp multi2.cpp catch.hpp) target_link_libraries(multifile_test ghc_filesystem) diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp index 9ba8039..847a745 100644 --- a/test/filesystem_test.cpp +++ b/test/filesystem_test.cpp @@ -88,8 +88,19 @@ using fstream = ghc::filesystem::fstream; #endif #include "catch.hpp" -//#define TEST_LWG_2935_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Behaviour Switches (should match the config in ghc/filesystem.hpp): +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories +#define TEST_LWG_2682_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular +// file with that name, it is superceded by P1164R1, so only activate if really needed +// #define TEST_LWG_2935_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) #define TEST_LWG_2937_BEHAVIOUR +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template std::time_t to_time_t(TP tp) @@ -474,13 +485,14 @@ TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.pat { #ifdef GHC_OS_WINDOWS #ifdef IS_WCHAR_PATH - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type(L"ä\\€")); + CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type(L"\u00E4\\\u20AC")); + // CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("ä\\€")); // MSVCs returns local DBCS encoding #else CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").native() == fs::path::string_type("\xc3\xa4\\\xe2\x82\xac")); + CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("\xc3\xa4\\\xe2\x82\xac")); CHECK(!::strcmp(fs::u8path("\xc3\xa4\\\xe2\x82\xac").c_str(), "\xc3\xa4\\\xe2\x82\xac")); CHECK((std::string)fs::u8path("\xc3\xa4\\\xe2\x82\xac") == std::string("\xc3\xa4\\\xe2\x82\xac")); #endif - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").string() == std::string("\xc3\xa4\\\xe2\x82\xac")); CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").wstring() == std::wstring(L"\u00E4\\\u20AC")); CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::string("\xc3\xa4\\\xe2\x82\xac")); CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u16string() == std::u16string(u"\u00E4\\\u20AC")); @@ -502,7 +514,9 @@ TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.pat TEST_CASE("30.10.8.4.7 path generic format observers", "[filesystem][path][fs.path.generic.obs]") { #ifdef GHC_OS_WINDOWS +#ifndef IS_WCHAR_PATH CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_string() == std::string("\xc3\xa4/\xe2\x82\xac")); +#endif #ifndef USE_STD_FS auto t = fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_string, TestAllocator>(); CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac")); @@ -1361,6 +1375,9 @@ TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]") generateFile("dir1/file2"); fs::create_directory("dir1/dir2"); generateFile("dir1/dir2/file3"); +#ifdef TEST_LWG_2682_BEHAVIOUR + REQUIRE_THROWS_AS(fs::copy("dir1", "dir3", fs::copy_options::create_symlinks | fs::copy_options::recursive), fs::filesystem_error); +#else REQUIRE_NOTHROW(fs::copy("dir1", "dir3", fs::copy_options::create_symlinks | fs::copy_options::recursive)); CHECK(!ec); CHECK(fs::exists("dir3/file1")); @@ -1369,6 +1386,7 @@ TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]") CHECK(fs::is_symlink("dir3/file2")); CHECK(fs::exists("dir3/dir2/file3")); CHECK(fs::is_symlink("dir3/dir2/file3")); +#endif } { TemporaryDirectory t(TempOpt::change_path); @@ -1471,7 +1489,7 @@ TEST_CASE("30.10.15.6 create_directories", "[filesystem][operations][fs.op.creat CHECK(!fs::is_directory(p)); CHECK(!fs::create_directories(p, ec)); #else - INFO("This test expects conformance predating LWG #2935 result. (As suggested by WG21 P1164R0, implemented by GCC with issue #86910.)"); + INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)"); p = t.path() / "testfile"; generateFile(p); CHECK(fs::is_regular_file(p)); @@ -1515,7 +1533,7 @@ TEST_CASE("30.10.15.7 create_directory", "[filesystem][operations][fs.op.create_ CHECK(!fs::is_directory(p)); CHECK(!fs::create_directories(p, ec)); #else - INFO("This test expects conformance predating LWG #2935 result. (As suggested by WG21 P1164R0, implemented by GCC with issue #86910.)"); + INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)"); p = t.path() / "testfile"; generateFile(p); CHECK(fs::is_regular_file(p)); @@ -1618,7 +1636,7 @@ TEST_CASE("30.10.15.12 equivalent", "[filesystem][operations][fs.op.equivalent]" INFO("This test expects LWG #2937 result conformance."); std::error_code ec; bool result = false; - CHECK_THROWS_AS(fs::equivalent("foo", "foo3"), fs::filesystem_error); + REQUIRE_THROWS_AS(fs::equivalent("foo", "foo3"), fs::filesystem_error); CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec)); CHECK(!result); CHECK(ec); @@ -1636,7 +1654,7 @@ TEST_CASE("30.10.15.12 equivalent", "[filesystem][operations][fs.op.equivalent]" INFO("This test expects conformance predating LWG #2937 result."); std::error_code ec; bool result = false; - CHECK_NOTHROW(result = fs::equivalent("foo", "foo3")); + REQUIRE_NOTHROW(result = fs::equivalent("foo", "foo3")); CHECK(!result); CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec)); CHECK(!result); @@ -2356,9 +2374,18 @@ TEST_CASE("30.10.15.38 temporary_directory_path", "[filesystem][operations][fs.o TEST_CASE("30.10.15.39 weakly_canonical", "[filesystem][operations][fs.op.weakly_canonical]") { - CHECK(fs::weakly_canonical("foo/bar") == "foo/bar"); - CHECK(fs::weakly_canonical("foo/./bar") == "foo/bar"); - CHECK(fs::weakly_canonical("foo/../bar") == "bar"); + INFO("This might fail on std::implementations that return fs::current_path() for fs::canonical(\"\")"); + CHECK(fs::weakly_canonical("") == "."); + if(fs::weakly_canonical("") == ".") { + CHECK(fs::weakly_canonical("foo/bar") == "foo/bar"); + CHECK(fs::weakly_canonical("foo/./bar") == "foo/bar"); + CHECK(fs::weakly_canonical("foo/../bar") == "bar"); + } + else { + CHECK(fs::weakly_canonical("foo/bar") == fs::current_path() / "foo/bar"); + CHECK(fs::weakly_canonical("foo/./bar") == fs::current_path() / "foo/bar"); + CHECK(fs::weakly_canonical("foo/../bar") == fs::current_path() / "bar"); + } { TemporaryDirectory t(TempOpt::change_path); @@ -2369,8 +2396,10 @@ TEST_CASE("30.10.15.39 weakly_canonical", "[filesystem][operations][fs.op.weakly CHECK(fs::weakly_canonical(dir) == dir); CHECK(fs::weakly_canonical(rel) == dir); CHECK(fs::weakly_canonical(dir / "f0") == dir / "f0"); + CHECK(fs::weakly_canonical(dir / "f0/") == dir / "f0/"); CHECK(fs::weakly_canonical(dir / "f1") == dir / "f1"); CHECK(fs::weakly_canonical(rel / "f0") == dir / "f0"); + CHECK(fs::weakly_canonical(rel / "f0/") == dir / "f0/"); CHECK(fs::weakly_canonical(rel / "f1") == dir / "f1"); CHECK(fs::weakly_canonical(rel / "./f0") == dir / "f0"); CHECK(fs::weakly_canonical(rel / "./f1") == dir / "f1");