Merge remote-tracking branch 'origin/master' into development-v1.1

# Conflicts:
#	.travis.yml
#	README.md
#	examples/du.cpp
#	include/ghc/filesystem.hpp
#	test/filesystem_test.cpp
This commit is contained in:
Steffen Schuemann 2019-05-13 00:21:32 +02:00
commit 3b5c3d4317
8 changed files with 242 additions and 98 deletions

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.9) cmake_minimum_required(VERSION 3.7.2)
project(ghcfilesystem) project(ghcfilesystem)
if(NOT DEFINED CMAKE_CXX_STANDARD) if(NOT DEFINED CMAKE_CXX_STANDARD)
@ -32,3 +32,19 @@ if(NOT hasParent)
add_subdirectory(test) add_subdirectory(test)
add_subdirectory(examples) add_subdirectory(examples)
endif() endif()
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
set(PACKAGECONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
configure_package_config_file(cmake/config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
INSTALL_DESTINATION ${PACKAGECONFIG_INSTALL_DIR}
PATH_VARS INCLUDE_INSTALL_DIR)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
DESTINATION ${PACKAGECONFIG_INSTALL_DIR})

View File

@ -1,7 +1,7 @@
![Supported Platforms](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue.svg) ![Supported Platforms](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue.svg)
[![Build Status](https://travis-ci.org/gulrak/filesystem.svg?branch=master)](https://travis-ci.org/gulrak/filesystem) [![Build Status](https://travis-ci.org/gulrak/filesystem.svg?branch=master)](https://travis-ci.org/gulrak/filesystem)
[![Build status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem) [![Build status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem)
![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg) [![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.1.4)
# Filesystem # Filesystem
@ -97,6 +97,11 @@ in the standard, and there might be issues in these implementations too.
## Usage ## Usage
### Downloads
The latest release version is [v1.1.4](https://github.com/gulrak/filesystem/tree/v1.1.4) and
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.1.4).
### Using it as Single-File-Header ### Using it as Single-File-Header
As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header
@ -291,18 +296,20 @@ between this and the standard C++17 API.
### LWG Defects ### LWG Defects
This implementation has switchable behavior for the LWG defects This implementation has switchable behavior for the LWG defects
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937). [#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937).
The currently selected behavior is following The currently selected behavior is following
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but [#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but
not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935), not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
as I feel it is a bug to report no error on a `create_directory()` or `create_directories()` as I feel it is a bug to report no error on a `create_directory()` or `create_directories()`
where a regular file of the same name prohibits the creation of a directory and forces where a regular file of the same name prohibits the creation of a directory and forces
the user of those functions to double-check via `fs::is_directory` if it really worked. the user of those functions to double-check via `fs::is_directory` if it really worked.
The more intuitive approach to directory creation of treating a file with that name as an
Update: The more intuitive approach to directory creation of treating a file with that name as an
error is also advocated by the newer paper error is also advocated by the newer paper
[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf) [WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revison
P1161R1 was agreed upon on Kona 2019 meeting [see merge](https://github.com/cplusplus/draft/issues/2703)
and GCC by now switched to following its proposal and GCC by now switched to following its proposal
([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)). ([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)).
@ -438,6 +445,35 @@ to the expected behavior.
## Release Notes ## Release Notes
### [v1.1.4](https://github.com/gulrak/filesystem/releases/tag/v1.1.4)
* Additional Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
error in old unified `readdir/readdir_r` code of `fs::directory_iterator`;
as `readdir_r` is now depricated, I decided to drop it and the resulting
code is much easier, shorter and due to more refactoring faster
* Fix for crashing unit tests against MSVC C++17 std::filesystem
* Travis-CI now additionally test with Xcode 10.2 on macOS
* Some minor refactorings
### [v1.1.2](https://github.com/gulrak/filesystem/releases/tag/v1.1.2)
* Bugfix for ([#11](https://github.com/gulrak/filesystem/issues/11)),
`fs::path::lexically_normal()` had some issues with `".."`-sequences.
* Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
`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) ### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0)
* Restructuring of the project directory. The header files are now using * Restructuring of the project directory. The header files are now using

5
cmake/config.cmake.in Normal file
View File

@ -0,0 +1,5 @@
@PACKAGE_INIT@
set_and_check(ghcfilesystem_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@")
check_required_components(ghcfilesystem)

View File

@ -29,11 +29,22 @@ int main(int argc, char* argv[])
} }
uint64_t totalSize = 0; uint64_t totalSize = 0;
int totalDirs = 0;
int totalFiles = 0;
int maxDepth = 0;
try { try {
for(auto de : fs::recursive_directory_iterator(dir)) { auto rdi = fs::recursive_directory_iterator(dir);
for(auto de : rdi) {
if(rdi.depth() > maxDepth) {
maxDepth = rdi.depth();
}
if(de.is_regular_file()) { if(de.is_regular_file()) {
totalSize += de.file_size(); totalSize += de.file_size();
++totalFiles;
}
else if(de.is_directory()) {
++totalDirs;
} }
} }
} }
@ -41,6 +52,6 @@ int main(int argc, char* argv[])
std::cerr << "Error: " << fe.what() << std::endl; std::cerr << "Error: " << fe.what() << std::endl;
exit(1); exit(1);
} }
std::cout << totalSize << std::endl; std::cout << totalSize << " bytes in " << totalFiles << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl;
return 0; return 0;
} }

View File

@ -129,6 +129,7 @@
#include <stack> #include <stack>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <system_error>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -143,13 +144,23 @@
#include <system_error> #include <system_error>
#endif // GHC_EXPAND_IMPL #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 #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 // #define LWG_2935_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
#define LWG_2937_BEHAVIOUR #define LWG_2937_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
#define GHC_FILESYSTEM_VERSION 10103L #define GHC_FILESYSTEM_VERSION 10105L
namespace ghc { namespace ghc {
namespace filesystem { namespace filesystem {
@ -332,6 +343,8 @@ public:
iterator end() const; iterator end() const;
private: private:
friend class directory_iterator;
void append_name(const char* name);
static constexpr value_type generic_separator = '/'; static constexpr value_type generic_separator = '/';
template <typename InputIterator> template <typename InputIterator>
class input_iterator_range class input_iterator_range
@ -727,13 +740,14 @@ public:
void swap(recursive_directory_iterator& rhs); void swap(recursive_directory_iterator& rhs);
private: private:
struct recursive_directory_iterator_impl { struct recursive_directory_iterator_impl
{
directory_options _options; directory_options _options;
bool _recursion_pending; bool _recursion_pending;
std::stack<directory_iterator> _dir_iter_stack; std::stack<directory_iterator> _dir_iter_stack;
recursive_directory_iterator_impl(directory_options options, bool recursion_pending) recursive_directory_iterator_impl(directory_options options, bool recursion_pending)
: _options(options) : _options(options)
, _recursion_pending(recursion_pending) , _recursion_pending(recursion_pending)
{ {
} }
}; };
@ -1042,7 +1056,11 @@ GHC_INLINE std::error_code make_error_code(portable_error err)
case portable_error::invalid_argument: case portable_error::invalid_argument:
return std::error_code(ERROR_INVALID_PARAMETER, std::system_category()); return std::error_code(ERROR_INVALID_PARAMETER, std::system_category());
case portable_error::is_a_directory: case portable_error::is_a_directory:
#ifdef ERROR_DIRECTORY_NOT_SUPPORTED
return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category());
#else
return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
#endif
} }
#else #else
switch (err) { switch (err) {
@ -1198,7 +1216,7 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT
unsigned utf8_state = S_STRT; unsigned utf8_state = S_STRT;
std::uint32_t codepoint = 0; std::uint32_t codepoint = 0;
while (iter < utf8String.end()) { while (iter < utf8String.end()) {
if (!(utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint))) { if ((utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint)) == S_STRT) {
if (sizeof(typename StringType::value_type) == 4) { if (sizeof(typename StringType::value_type) == 4) {
result += codepoint; result += codepoint;
} }
@ -1899,7 +1917,8 @@ inline path& path::assign(const Source& source)
template <> template <>
inline path& path::assign<path>(const path& source) inline path& path::assign<path>(const path& source)
{ {
return assign(source._path); _path = source._path;
return *this;
} }
template <class InputIterator> template <class InputIterator>
@ -1949,6 +1968,19 @@ GHC_INLINE path& path::operator/=(const path& p)
return *this; return *this;
} }
GHC_INLINE void path::append_name(const char* name)
{
if (_path.empty()) {
this->operator/=(path(name));
}
else {
if (_path.back() != path::generic_separator) {
_path.push_back(path::generic_separator);
}
_path += name;
}
}
#endif // GHC_EXPAND_IMPL #endif // GHC_EXPAND_IMPL
template <class Source> template <class Source>
@ -2401,7 +2433,7 @@ GHC_INLINE path path::lexically_normal() const
continue; continue;
} }
else if (*(--dest.end()) != "..") { else if (*(--dest.end()) != "..") {
if(dest._path.back() == generic_separator) { if (dest._path.back() == generic_separator) {
dest._path.pop_back(); dest._path.pop_back();
} }
dest.remove_filename(); dest.remove_filename();
@ -2988,7 +3020,7 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options, std
} }
} }
#ifdef LWG_2682_BEHAVIOUR #ifdef LWG_2682_BEHAVIOUR
else if(is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { 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); ec = detail::make_error_code(detail::portable_error::is_a_directory);
} }
#endif #endif
@ -4527,7 +4559,8 @@ public:
if (_dirHandle != INVALID_HANDLE_VALUE) { if (_dirHandle != INVALID_HANDLE_VALUE) {
do { do {
if (FindNextFileW(_dirHandle, &_findData)) { if (FindNextFileW(_dirHandle, &_findData)) {
_current = _base / std::wstring(_findData.cFileName); _current = _base;
_current.append_name(detail::toUtf8(_findData.cFileName).c_str());
copyToDirEntry(ec); copyToDirEntry(ec);
} }
else { else {
@ -4574,32 +4607,16 @@ public:
// POSIX implementation // POSIX implementation
class directory_iterator::impl class directory_iterator::impl
{ {
size_t directory_entry_buffer_size(DIR* d)
{
size_t result = std::max(sizeof(::dirent), sizeof(::dirent) - sizeof(::dirent::d_name) + NAME_MAX) + 1;
if (d) {
long rc = ::fpathconf(dirfd(d), _PC_NAME_MAX);
if (rc > long(result)) {
result = static_cast<size_t>(rc);
}
}
return result;
}
public: public:
impl(const path& path, directory_options options) impl(const path& path, directory_options options)
: _base(path) : _base(path)
, _options(options) , _options(options)
, _dir((path.empty() ? nullptr : ::opendir(path.native().c_str())), , _dir(nullptr)
[](DIR* d) { , _entry(nullptr)
if (d) {
::closedir(d);
}
})
, _bufferSize(directory_entry_buffer_size(_dir.get()))
, _buffer(new char[_bufferSize])
, _entry(reinterpret_cast<::dirent*>(&_buffer[0]))
{ {
if (!path.empty()) {
_dir = ::opendir(path.native().c_str());
}
if (!path.empty()) { if (!path.empty()) {
if (!_dir) { if (!_dir) {
auto error = errno; auto error = errno;
@ -4614,40 +4631,30 @@ public:
} }
} }
impl(const impl& other) = delete; impl(const impl& other) = delete;
int i_readdir_r(DIR* dir, struct dirent* entry, struct dirent** result) ~impl()
{ {
#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24)) if (_dir) {
errno = 0; ::closedir(_dir);
auto de = readdir(dir);
if (de) {
*entry = *de;
*result = entry;
return 0;
} }
return errno;
#else
return ::readdir_r(dir, entry, result);
#endif
} }
void increment(std::error_code& ec) void increment(std::error_code& ec)
{ {
if (_dir) { if (_dir) {
do { do {
dirent* result = 0; errno = 0;
if (0 == i_readdir_r(_dir.get(), _entry, &result)) { _entry = readdir(_dir);
if (result) { if (_entry) {
_current = _base / path(_entry->d_name); _current = _base;
_dir_entry = directory_entry(_current, ec); _current.append_name(_entry->d_name);
} _dir_entry = directory_entry(_current, ec);
else {
_dir.reset();
_current = path();
break;
}
} }
else { else {
::closedir(_dir);
_dir = nullptr;
_current = path(); _current = path();
ec = std::error_code(errno, std::system_category()); if (errno) {
ec = std::error_code(errno, std::system_category());
}
break; break;
} }
} while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); } while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0);
@ -4656,9 +4663,7 @@ public:
path _base; path _base;
directory_options _options; directory_options _options;
path _current; path _current;
std::shared_ptr<DIR> _dir; DIR* _dir;
size_t _bufferSize;
std::unique_ptr<char[]> _buffer;
struct ::dirent* _entry; struct ::dirent* _entry;
directory_entry _dir_entry; directory_entry _dir_entry;
std::error_code _ec; std::error_code _ec;
@ -4883,9 +4888,14 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment
else { else {
_impl->_dir_iter_stack.top().increment(ec); _impl->_dir_iter_stack.top().increment(ec);
} }
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { if (!ec) {
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
_impl->_dir_iter_stack.pop();
_impl->_dir_iter_stack.top().increment(ec);
}
}
else if (!_impl->_dir_iter_stack.empty()) {
_impl->_dir_iter_stack.pop(); _impl->_dir_iter_stack.pop();
_impl->_dir_iter_stack.top().increment(ec);
} }
_impl->_recursion_pending = true; _impl->_recursion_pending = true;
return *this; return *this;
@ -4906,10 +4916,10 @@ GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec)
*this = recursive_directory_iterator(); *this = recursive_directory_iterator();
} }
else { else {
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { do {
_impl->_dir_iter_stack.pop(); _impl->_dir_iter_stack.pop();
_impl->_dir_iter_stack.top().increment(ec); _impl->_dir_iter_stack.top().increment(ec);
} } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator());
} }
} }

View File

@ -33,7 +33,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_std.hpp - The dynamic switching header for that includes std::filesystem if detected // fs_std.hpp - The dynamic switching header that includes std::filesystem if detected
// or ghc::filesystem if not, and makes the resulting API available in the // or ghc::filesystem if not, and makes the resulting API available in the
// namespace fs. // namespace fs.
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------

View File

@ -36,6 +36,7 @@
#include <functional> #include <functional>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <map>
#include <random> #include <random>
#include <sstream> #include <sstream>
#include <thread> #include <thread>
@ -87,28 +88,34 @@ using fstream = ghc::filesystem::fstream;
#endif #endif
#include "catch.hpp" #include "catch.hpp"
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 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 #define TEST_LWG_2682_BEHAVIOUR
//#define TEST_LWG_2935_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 #define TEST_LWG_2937_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template <typename TP> template <typename TP>
std::time_t to_time_t(TP tp) std::time_t to_time_t(TP tp)
{ {
// Based on trick from: Nico Josuttis, C++17 - The Complete Guide
using namespace std::chrono; using namespace std::chrono;
auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now()); auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now());
//system_clock::duration dt = duration_cast<system_clock::duration>(tp - TP::clock::now());
return system_clock::to_time_t(sctp); return system_clock::to_time_t(sctp);
} }
template <typename TP> template <typename TP>
TP from_time_t(std::time_t t) TP from_time_t(std::time_t t)
{ {
// Based on trick from: Nico Josuttis, C++17 - The Complete Guide
using namespace std::chrono; using namespace std::chrono;
auto sctp = system_clock::from_time_t(t); auto sctp = system_clock::from_time_t(t);
auto tp = time_point_cast<TP::duration>(sctp - system_clock::now() + TP::clock::now()); auto tp = time_point_cast<TP::duration>(sctp - system_clock::now() + TP::clock::now());
// system_clock::duration dt = duration_cast<system_clock::duration>(tp - TP::clock::now());
return tp; return tp;
} }
@ -288,7 +295,7 @@ bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept
return !(x == y); return !(x == y);
} }
TEST_CASE("Temporary Directory", "[temp dir]") TEST_CASE("Temporary Directory", "[fs.test.tempdir]")
{ {
fs::path tempPath; fs::path tempPath;
{ {
@ -300,6 +307,21 @@ TEST_CASE("Temporary Directory", "[temp dir]")
REQUIRE(!fs::exists(tempPath)); REQUIRE(!fs::exists(tempPath));
} }
#ifdef GHC_FILESYSTEM_VERSION
TEST_CASE("fs::detail::fromUf88", "[filesystem][fs.detail.utf8]")
{
CHECK(fs::detail::fromUtf8<std::wstring>("foobar").length() == 6);
CHECK(fs::detail::fromUtf8<std::wstring>("foobar") == L"foobar");
CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar").length() == 6);
CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar") == L"föobar");
CHECK(fs::detail::toUtf8(std::wstring(L"foobar")).length() == 6);
CHECK(fs::detail::toUtf8(std::wstring(L"foobar")) == "foobar");
CHECK(fs::detail::toUtf8(std::wstring(L"föobar")).length() == 7);
CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar");
}
#endif
#ifndef GHC_OS_WINDOWS #ifndef GHC_OS_WINDOWS
TEST_CASE("30.10.8.1 path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]") TEST_CASE("30.10.8.1 path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]")
{ {
@ -1228,29 +1250,73 @@ TEST_CASE("30.10.14 class recursive_directory_iterator", "[filesystem][recursive
fs::recursive_directory_iterator rd5; fs::recursive_directory_iterator rd5;
rd5 = rd4; rd5 = rd4;
} }
/* {
if(1) { TemporaryDirectory t(TempOpt::change_path);
fs::path d = ".."; generateFile("a");
int maxDepth = 2; fs::create_directory("d1");
fs::recursive_directory_iterator dit(d); fs::create_directory("d1/d2");
std::cout << d << std::endl; generateFile("d1/b");
for(auto & f : dit) { generateFile("d1/c");
#if 1 generateFile("d1/d2/d");
if(dit.depth()<=maxDepth) { generateFile("e");
std::cout << dit.depth() << ": " << f.path() << std::endl; auto iter = fs::recursive_directory_iterator(".");
std::multimap<std::string, int> result;
while(iter != fs::recursive_directory_iterator()) {
result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
++iter;
}
std::stringstream os;
for(auto p : result) {
os << "[" << p.first << "," << p.second << "],";
}
CHECK(os.str() == "[./a,0],[./d1,0],[./d1/b,1],[./d1/c,1],[./d1/d2,1],[./d1/d2/d,2],[./e,0],");
}
{
TemporaryDirectory t(TempOpt::change_path);
generateFile("a");
fs::create_directory("d1");
fs::create_directory("d1/d2");
generateFile("d1/d2/b");
generateFile("e");
auto iter = fs::recursive_directory_iterator(".");
std::multimap<std::string, int> result;
while(iter != fs::recursive_directory_iterator()) {
result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
if(iter->path() == "./d1/d2") {
iter.disable_recursion_pending();
}
++iter;
}
std::stringstream os;
for(auto p : result) {
os << "[" << p.first << "," << p.second << "],";
}
CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
}
{
TemporaryDirectory t(TempOpt::change_path);
generateFile("a");
fs::create_directory("d1");
fs::create_directory("d1/d2");
generateFile("d1/d2/b");
generateFile("e");
auto iter = fs::recursive_directory_iterator(".");
std::multimap<std::string, int> result;
while(iter != fs::recursive_directory_iterator()) {
result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
if(iter->path() == "./d1/d2") {
iter.pop();
} }
else { else {
dit.pop(); ++iter;
} }
#else
std::cout << dit.depth() << ": " << f.path() << std::endl;
if(dit.depth()>maxDepth) {
dit.disable_recursion_pending();
}
#endif
} }
std::stringstream os;
for(auto p : result) {
os << "[" << p.first << "," << p.second << "],";
}
CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
} }
*/
} }
TEST_CASE("30.10.15.1 absolute", "[filesystem][operations][fs.op.absolute]") TEST_CASE("30.10.15.1 absolute", "[filesystem][operations][fs.op.absolute]")
@ -1447,7 +1513,7 @@ TEST_CASE("30.10.15.6 create_directories", "[filesystem][operations][fs.op.creat
CHECK(!fs::is_directory(p)); CHECK(!fs::is_directory(p));
CHECK(!fs::create_directories(p, ec)); CHECK(!fs::create_directories(p, ec));
#else #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"; p = t.path() / "testfile";
generateFile(p); generateFile(p);
CHECK(fs::is_regular_file(p)); CHECK(fs::is_regular_file(p));
@ -1491,7 +1557,7 @@ TEST_CASE("30.10.15.7 create_directory", "[filesystem][operations][fs.op.create_
CHECK(!fs::is_directory(p)); CHECK(!fs::is_directory(p));
CHECK(!fs::create_directories(p, ec)); CHECK(!fs::create_directories(p, ec));
#else #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"; p = t.path() / "testfile";
generateFile(p); generateFile(p);
CHECK(fs::is_regular_file(p)); CHECK(fs::is_regular_file(p));