diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index 86a63f6b..0b4efa5c 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -68,12 +68,14 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp Library/Chrono/Timer.cpp Library/Chrono/Timer.hpp Library/Chrono/Timestamp.cpp Library/Chrono/Timestamp.hpp Library/CURL.cpp Library/CURL.hpp + Library/FileSystem.cpp Library/FileSystem.hpp Library/Format.cpp Library/Format.hpp Library/IO.cpp Library/IO.hpp Library/IO/Buffer.cpp Library/IO/Buffer.hpp Library/IO/File.cpp Library/IO/File.hpp Library/IO/INI.cpp Library/IO/INI.hpp Library/IO/Stream.cpp Library/IO/Stream.hpp + Library/JSON.cpp Library/JSON.hpp Library/MMDB.cpp Library/MMDB.hpp Library/Numeric.cpp Library/Numeric.hpp Library/Numeric/Long.cpp Library/Numeric/Long.hpp @@ -132,7 +134,7 @@ if(WIN32 OR MINGW) target_link_libraries(SqModule wsock32 ws2_32 shlwapi) endif() # Link to base libraries -target_link_libraries(SqModule Squirrel ghc_filesystem fmt::fmt SimpleINI TinyDir ConcurrentQueue CPR PUGIXML maxminddb jansson libzmq-static) +target_link_libraries(SqModule Squirrel fmt::fmt SimpleINI TinyDir ConcurrentQueue CPR PUGIXML maxminddb libzmq-static) # Link to POCO libraries target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net Poco::JSON Poco::XML) # Does POCO have SQLite support? @@ -141,7 +143,7 @@ if(ENABLE_DATA_SQLITE) # We need to make sqlite3.h available for include. Ugly but POCO doesn't expose this directly. target_include_directories(SqModule PRIVATE "${PROJECT_SOURCE_DIR}/vendor/POCO/Data/SQLite/src") endif() - message(STATUS SQLite was enabled) + message(STATUS "SQLite was enabled") # Link the libraries target_link_libraries(SqModule Poco::DataSQLite) # Inform the plug-in that it can make use of this library @@ -152,7 +154,7 @@ endif() # Does POCO have MySLQ support? find_package(MySQL) if(MYSQL_FOUND) - message(STATUS MySQL was enabled) + message(STATUS "MySQL was enabled") # Link the libraries target_link_libraries(SqModule Poco::DataMySQL) # Inform the plug-in that it can make use of this library diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index fef8686e..115809d1 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -47,5 +47,4 @@ set(BUILD_STATIC ON CACHE INTERNAL "" FORCE) if (WIN32 OR MINGW) set(ZMQ_HAVE_IPC OFF CACHE INTERNAL "" FORCE) endif() -add_subdirectory(ZMQ) -add_subdirectory(FileSystem) \ No newline at end of file +add_subdirectory(ZMQ) \ No newline at end of file diff --git a/vendor/FileSystem/CMakeLists.txt b/vendor/FileSystem/CMakeLists.txt deleted file mode 100644 index f6b7f549..00000000 --- a/vendor/FileSystem/CMakeLists.txt +++ /dev/null @@ -1,74 +0,0 @@ -cmake_minimum_required(VERSION 3.7.2) -project(ghcfilesystem) - -if (POLICY CMP0077) - cmake_policy(SET CMP0077 NEW) -endif() -if(POLICY CMP0110) - cmake_policy(SET CMP0110 NEW) -endif() - -if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - option(GHC_FILESYSTEM_BUILD_TESTING "Enable tests" ON) - option(GHC_FILESYSTEM_BUILD_EXAMPLES "Build examples" ON) - option(GHC_FILESYSTEM_WITH_INSTALL "With install target" ON) -else() - option(GHC_FILESYSTEM_BUILD_EXAMPLES "Build examples" OFF) - option(GHC_FILESYSTEM_BUILD_TESTING "Enable tests" OFF) - option(GHC_FILESYSTEM_WITH_INSTALL "With install target" ON) -endif() -option(GHC_FILESYSTEM_BUILD_STD_TESTING "Enable STD tests" ${GHC_FILESYSTEM_BUILD_TESTING}) -if(NOT DEFINED GHC_FILESYSTEM_TEST_COMPILE_FEATURES) - set(GHC_FILESYSTEM_TEST_COMPILE_FEATURES ${CMAKE_CXX_COMPILE_FEATURES}) -endif() - -if(NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - if(NOT CYGWIN) - set(CMAKE_CXX_EXTENSIONS OFF) - endif() -endif() -if(CMAKE_CXX_STANDARD LESS 11) - message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.") -endif() -message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}") - -add_library(ghc_filesystem INTERFACE) -target_include_directories(ghc_filesystem INTERFACE - $ - $) -target_compile_options(ghc_filesystem INTERFACE "$<$:/utf-8>") -target_compile_options(ghc_filesystem INTERFACE "$<$:/utf-8>") - -if(GHC_FILESYSTEM_BUILD_TESTING OR GHC_FILESYSTEM_BUILD_EXAMPLES) - set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") - include(GhcHelper) - - if(GHC_FILESYSTEM_BUILD_TESTING) - enable_testing() - add_subdirectory(test) - endif() - - if(GHC_FILESYSTEM_BUILD_EXAMPLES) - add_subdirectory(examples) - endif() -endif() - -if(GHC_FILESYSTEM_WITH_INSTALL) - include(CMakePackageConfigHelpers) - include(GNUInstallDirs) - install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - install(TARGETS ghc_filesystem EXPORT ghc_filesystem-targets) - install(EXPORT ghc_filesystem-targets NAMESPACE ghcFilesystem:: DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem") - export(EXPORT ghc_filesystem-targets NAMESPACE ghcFilesystem:: FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/ghc_filesystem-targets.cmake") - configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.cmake.in" - "${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem" - PATH_VARS CMAKE_INSTALL_INCLUDEDIR) - install(FILES "${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem") - add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem) -endif() diff --git a/vendor/FileSystem/LICENSE b/vendor/FileSystem/LICENSE deleted file mode 100644 index 8b24faa7..00000000 --- a/vendor/FileSystem/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2018, Steffen Schümann - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/FileSystem/README.md b/vendor/FileSystem/README.md deleted file mode 100644 index 9043ab6f..00000000 --- a/vendor/FileSystem/README.md +++ /dev/null @@ -1,1054 +0,0 @@ -![Supported Platforms](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows%20%7C%20FreeBSD-blue.svg) -![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg) -[![CMake Build Matrix](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml/badge.svg?branch=master)](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml) -[![Build Status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem) -[![Build Status](https://api.cirrus-ci.com/github/gulrak/filesystem.svg?branch=master)](https://cirrus-ci.com/github/gulrak/filesystem) -[![Build Status](https://cloud.drone.io/api/badges/gulrak/filesystem/status.svg?ref=refs/heads/master)](https://cloud.drone.io/gulrak/filesystem) -[![Coverage Status](https://coveralls.io/repos/github/gulrak/filesystem/badge.svg?branch=master)](https://coveralls.io/github/gulrak/filesystem?branch=master) -[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.5.8) - -- [Filesystem](#filesystem) - - [Motivation](#motivation) - - [Why the namespace GHC?](#why-the-namespace-ghc) - - [Platforms](#platforms) - - [Tests](#tests) - - [Usage](#usage) - - [Downloads](#downloads) - - [Using it as Single-File-Header](#using-it-as-single-file-header) - - [Using it as Forwarding-/Implementation-Header](#using-it-as-forwarding-implementation-header) - - [Git Submodule and CMake](#git-submodule-and-cmake) - - [Versioning](#versioning) - - [Documentation](#documentation) - - [`ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream`](#ghcfilesystemifstream-ghcfilesystemofstream-ghcfilesystemfstream) - - [`ghc::filesystem::u8arguments`](#ghcfilesystemu8arguments) - - [Differences](#differences) - - [LWG Defects](#lwg-defects) - - [Not Implemented on C++ before C++17](#not-implemented-on-c-before-c17) - - [Differences in API](#differences-in-api) - - [Differences of Specific Interfaces](#differences-of-specific-interfaces) - - [Differences in Behavior](#differences-in-behavior) - - [fs.path](#fspath-refhttpsencppreferencecomwcppfilesystempath) - - [Open Issues](#open-issues) - - [Windows](#windows) - - [Symbolic Links on Windows](#symbolic-links-on-windows) - - [Permissions](#permissions) - - [Release Notes](#release-notes) - -# Filesystem - -This is a header-only single-file `std::filesystem` compatible helper library, -based on the C++17 and C++20 specs, but implemented for C++11, C++14, C++17 or C++20 -(tightly following the C++17 standard with very few documented exceptions). It is currently tested on -macOS 10.12/10.14/10.15, Windows 10, Ubuntu 18.04, Ubuntu 20.04, CentOS 7, CentOS 8, FreeBSD 12 -and Alpine ARM/ARM64 Linux but should work on other systems too, as long as you have -at least a C++11 compatible compiler. It should work with Android NDK, Emscripten and I even -had reports of it being used on iOS (within sandboxing constraints) and with v1.5.6 there -is experimental support for QNX. The support of Android NDK, Emscripten and QNX is not -backed up by automated testing but PRs and bug reports are welcome for those too. -It is of course in its own namespace `ghc::filesystem` to not interfere with a regular `std::filesystem` -should you use it in a mixed C++17 environment (which is possible). - -*Test coverage is well above 90%, and starting with v1.3.6 and in v1.5.0 -more time was invested in benchmarking and optimizing parts of the library. I'll try -to continue to optimize some parts and refactor others, striving -to improve it as long as it doesn't introduce additional C++17/C++20 compatibility -issues. Feedback is always welcome. Simply open an issue if you see something missing -or wrong or not behaving as expected and I'll comment.* - - -## Motivation - -I'm often in need of filesystem functionality, mostly `fs::path`, but directory -access too, and when beginning to use C++11, I used that language update -to try to reduce my third-party dependencies. I could drop most of what -I used, but still missed some stuff that I started implementing for the -fun of it. Originally I based these helpers on my own coding- and naming -conventions. When C++17 was finalized, I wanted to use that interface, -but it took a while, to push myself to convert my classes. - -The implementation is closely based on chapter 30.10 from the C++17 standard -and a draft close to that version is -[Working Draft N4687](https://github.com/cplusplus/draft/raw/master/papers/n4687.pdf). -It is from after the standardization of C++17 but it contains the latest filesystem -interface changes compared to the -[Working Draft N4659](https://github.com/cplusplus/draft/raw/master/papers/n4659.pdf). -Staring with v1.4.0, when compiled using C++20, it adapts to the changes according to path sorting order -and `std::u8string` handling from [Working Draft N4860](https://isocpp.org/files/papers/N4860.pdf). - -I want to thank the people working on improving C++, I really liked how the language -evolved with C++11 and the following standards. Keep on the good work! - -## Why the namespace GHC? -If you ask yourself, what `ghc` is standing for, it is simply -`gulraks helper classes`, yeah, I know, not very imaginative, but I wanted a -short namespace and I use it in some of my private classes (so **it has nothing -to do with Haskell**, sorry for the name clash). - -## Platforms - -`ghc::filesystem` is developed on macOS but CI tested on macOS, Windows, -various Linux Distributions and FreeBSD. It should work on any of these with a C++11-capable -compiler. Also there are some checks to hopefully better work on Android, but -as I currently don't test with the Android NDK, I wouldn't call it a -supported platform yet, same is valid for using it with Emscripten. It is now -part of the detected platforms, I fixed the obvious issues and ran some tests with -it, so it should be fine. All in all, I don't see it replacing `std::filesystem` -where full C++17 or C++20 is available, it doesn't try to be a "better" -`std::filesystem`, just an almost drop-in if you can't use it (with the exception -of the UTF-8 preference). - -:information_source: **Important:** _This implementation is following the ["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/) in that all -`std::string` instances will be interpreted the same as `std::u8string` encoding -wise and as being in UTF-8. The `std::u16string` will be seen as UTF-16. See *Differences in API* -for more information._ - -Unit tests are currently run with: - -* macOS 10.12: Xcode 9.2 (clang-900.0.39.2), GCC 9.2, Clang 9.0, macOS 10.13: Xcode 10.1, macOS 10.14: Xcode 11.2, macOS 10.15: Xcode 11.6, Xcode 12.4 -* Windows: Visual Studio 2017, Visual Studio 2015, Visual Studio 2019, MinGW GCC 6.3 (Win32), GCC 7.2 (Win64), Cygwin GCC 10.2 (no CI yet) -* Linux (Ubuntu): GCC (5.5, 6.5, 7.4, 8.3, 9.2), Clang (5.0, 6.0, 7.1, 8.0, 9.0) -* Linux (Alpine ARM/ARM64): GCC 9.2.0 -* FreeBSD: Clang 8.0 - - -## Tests - -The header comes with a set of unit-tests and uses [CMake](https://cmake.org/) -as a build tool and [Catch2](https://github.com/catchorg/Catch2) as test framework. -All tests are registered with in CMake, so the [ctest](https://cmake.org/cmake/help/latest/manual/ctest.1.html) -commando can be used to run the tests. - -All tests against this implementation should succeed, depending on your environment -it might be that there are some warnings, e.g. if you have no rights to create -Symlinks on Windows or at least the test thinks so, but these are just informative. - -To build the tests from inside the project directory under macOS or Linux just: - -```cpp -mkdir build -cd build -cmake -DCMAKE_BUILD_TYPE=Debug .. -make -ctest -``` - -This generates the test binaries that run the tests and the last command executes -them. - -If the default compiler is a GCC 8 or newer, or Clang 7 or newer, it -additionally tries to build a version of the test binary compiled against GCCs/Clangs -`std::filesystem` implementation, named `std_filesystem_test` -as an additional test of conformance. Ideally all tests should compile and -succeed with all filesystem implementations, but in reality, there are -some differences in behavior, sometimes due to room for interpretation in -in the standard, and there might be issues in these implementations too. - - -## Usage - -### Downloads - -The latest release version is [v1.5.8](https://github.com/gulrak/filesystem/tree/v1.5.8) and -source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.5.8). - -The latest pre-native-backend version is [v1.4.0](https://github.com/gulrak/filesystem/tree/v1.4.0) and -source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.4.0). - -The latest pre-C++20-support release version is [v1.3.10](https://github.com/gulrak/filesystem/tree/v1.3.10) and -source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.3.10). - -Currently only the latest minor release version receives bugfixes, so if possible, -you should use the latest release. - -### Using it as Single-File-Header - -As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header -or the `include/ghc` directory into your project folder or point your include path to this place and -simply include the `filesystem.hpp` header (or `ghc/filesystem.hpp` if you use the subdirectory). - -Everything is in the namespace `ghc::filesystem`, so one way to use it only as -a fallback could be: - -```cpp -#ifdef __APPLE__ -#include // for deployment target to support pre-catalina targets without std::fs -#endif -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -#if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -#define GHC_USE_STD_FS -#include -namespace fs = std::filesystem; -#endif -#endif -#ifndef GHC_USE_STD_FS -#include -namespace fs = ghc::filesystem; -#endif -``` - -**Note that this code uses a two-stage preprocessor condition because Visual Studio 2015 -doesn't like the `(<...>)` syntax, even if it could cut evaluation early before. This code also -used the minimum deployment target to detect if `std::filesystem` really is available on macOS -compilation.** - -**Note also, this detection now works on MSVC versions prior to 15.7 on, or without setting -the `/Zc:__cplusplus` compile switch that would fix `__cplusplus` on MSVC. (Without the switch -the compiler always reports `199711L` -([see](https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/)), -but `_MSVC_LANG` works without it.** - -If you want to also use the `fstream` wrapper with `path` support as fallback, -you might use: - -```cpp -#ifdef __APPLE__ -#include // for deployment target to support pre-catalina targets without std::fs -#endif -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -#if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -#define GHC_USE_STD_FS -#include -namespace fs { -using namespace std::filesystem; -using ifstream = std::ifstream; -using ofstream = std::ofstream; -using fstream = std::fstream; -} -#endif -#endif -#ifndef GHC_USE_STD_FS -#include -namespace fs { -using namespace ghc::filesystem; -using ifstream = ghc::filesystem::ifstream; -using ofstream = ghc::filesystem::ofstream; -using fstream = ghc::filesystem::fstream; -} -#endif -``` - -Now you have e.g. `fs::ofstream out(somePath);` and it is either the wrapper or -the C++17 `std::ofstream`. - -:information_source: **Be aware, as a header-only library, it is not hiding the fact, that it -uses system includes, so they "pollute" your global namespace. Use the -forwarding-/implementation-header based approach (see below) to avoid this. -For Windows it needs `Windows.h` and it might be a good idea to define -`WIN32_LEAN_AND_MEAN` or `NOMINMAX` prior to including `filesystem.hpp` or -`fs_std.hpp` headers to reduce pollution of your global namespace and compile -time. They are not defined by `ghc::filesystem` to allow combination with contexts -where the full `Windows.h`is needed, e.g. for UI elements.** - -:information_source: **Hint:** There is an additional header named `ghc/fs_std.hpp` that implements this -dynamic selection of a filesystem implementation, that you can include -instead of `ghc/filesystem.hpp` when you want `std::filesystem` where -available and `ghc::filesystem` where not. - - -### Using it as Forwarding-/Implementation-Header - -Alternatively, starting from v1.1.0 `ghc::filesystem` can also be used by -including one of two additional wrapper headers. These allow to include -a forwarded version in most places (`ghc/fs_fwd.hpp`) while hiding the -implementation details in a single cpp file that includes `ghc/fs_impl.hpp` to -implement the needed code. Using `ghc::filesystem` this way makes sure -system includes are only visible from inside the cpp file, all other places are clean. - -Be aware, that it is currently not supported to hide the implementation -into a Windows-DLL, as a DLL interface with C++ standard templates in interfaces -is a different beast. If someone is willing to give it a try, I might integrate -a PR but currently working on that myself is not a priority. - -If you use the forwarding/implementation approach, you can still use the dynamic -switching like this: - -```cpp -#ifdef __APPLE__ -#include // for deployment target to support pre-catalina targets without std::fs -#endif -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -#if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -#define GHC_USE_STD_FS -#include -namespace fs { -using namespace std::filesystem; -using ifstream = std::ifstream; -using ofstream = std::ofstream; -using fstream = std::fstream; -} -#endif -#endif -#ifndef GHC_USE_STD_FS -#include -namespace fs { -using namespace ghc::filesystem; -using ifstream = ghc::filesystem::ifstream; -using ofstream = ghc::filesystem::ofstream; -using fstream = ghc::filesystem::fstream; -} -#endif -``` - -and in the implementation hiding cpp, you might use (before any include that includes `ghc/fs_fwd.hpp` -to take precedence: - -```cpp -#ifdef __APPLE__ // for deployment target to support pre-catalina targets without std::fs -#include -#endif -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -#if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -#define GHC_USE_STD_FS -#endif -#endif -#ifndef GHC_USE_STD_FS -#define GHC_FILESYSTEM_IMPLEMENTATION -#include -#endif -``` - -:information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and -`ghc/fs_std_impl.hpp` that use this technique, so you can simply include them -if you want to dynamically select the filesystem implementation. they also -enable the `wchar_t` support on `ghc::filesystem` on Windows, so the resulting -implementation in the `fs` namespace will be compatible. - - - -### Git Submodule and CMake - -Starting from v1.1.0, it is possible to add `ghc::filesystem` -as a git submodule, add the directory to your `CMakeLists.txt` with -`add_subdirectory()` and then simply use `target_link_libraries(your-target ghc_filesystem)` -to ensure correct include path that allow `#include ` -to work. - -The `CMakeLists.txt` offers a few options to customize its behavior: - -* `GHC_FILESYSTEM_BUILD_TESTING` - Compile tests, default is `OFF` when used as - a submodule, else `ON`. -* `GHC_FILESYSTEM_BUILD_EXAMPLES` - Compile the examples, default is `OFF` when used as - a submodule, else `ON`. -* `GHC_FILESYSTEM_WITH_INSTALL` - Add install target to build, default is `OFF` when used as - a submodule, else `ON`. -* `GHC_FILESYSTEM_BUILD_STD_TESTING` - Compile `std_filesystem_test`, the variant of - the test suite running against `std::filesystem`, defaulting to `GHC_FILESYSTEM_BUILD_TESTING`. - This is only done if the compiler is detected as being able to do it. -* `GHC_FILESYSTEM_TEST_COMPILE_FEATURES` can be set to a list of features to override - `CMAKE_CXX_COMPILE_FEATURES` when the detection of C++17 or C++20 for additional tests - is not working (e.g. `cxx_std_20` to enforce building a `filesystem_test_cpp20` with C++20). - -### Versioning - -There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes -might make it needed to react on the version, but I don't plan to break anything. -It's the version as decimal number `(major * 10000 + minor * 100 + patch)`. - -:information_source: **Note:** Only even patch versions will be used for releases -and odd patch version will only be used for in between commits while working on -the next version. - - -## Documentation - -There is almost no documentation in this release, as any `std::filesystem` -documentation would work, besides the few differences explained in the next -section. So you might head over to https://en.cppreference.com/w/cpp/filesystem -for a description of the components of this library. - -When compiling with C++11, C++14 or C++17, the API is following the C++17 -standard, where possible, with the exception that `std::string_view` parameters -are only supported on C++17. When Compiling with C++20, `ghc::filesysytem` -defaults to the C++20 API, with the `char8_t` and `std::u8string` interfaces -and the deprecated `fs::u8path` factory method. - -:information_source: **Note:** If the C++17 API should be enforced even in C++20 mode, -use the define `GHC_FILESYSTEM_ENFORCE_CPP17_API`. -Even then it is possible to create `fws::path` from `std::u8string` but -`fs::path::u8string()` and `fs::path::generic_u8string()` return normal -UTF-8 encoded `std::string` instances, so code written for C++17 could -still work with `ghc::filesystem` when compiled with C++20. - -The only additions to the standard are documented here: - - -### `ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream` - -These are simple wrappers around `std::ifstream`, `std::ofstream` and `std::fstream`. -They simply add an `open()` method and a constructor with an `ghc::filesystem::path` -argument as the `fstream` variants in C++17 have them. - -### `ghc::filesystem::u8arguments` - -This is a helper class that currently checks for UTF-8 encoding on non-Windows platforms but on Windows it -fetches the command line arguments as Unicode strings from the OS with - -```cpp -::CommandLineToArgvW(::GetCommandLineW(), &argc) -``` - -and then converts them to UTF-8, and replaces `argc` and `argv`. It is a guard-like -class that reverts its changes when going out of scope. - -So basic usage is: - -```cpp -namespace fs = ghc::filesystem; - -int main(int argc, char* argv[]) -{ - fs::u8arguments u8guard(argc, argv); - if(!u8guard.valid()) { - std::cerr << "Bad encoding, needs UTF-8." << std::endl; - exit(EXIT_FAILURE); - } - - // now use argc/argv as usual, they have utf-8 enconding on windows - // ... - - return 0; -} -``` - -That way `argv` is UTF-8 encoded as long as the scope from `main` is valid. - -**Note:** On macOS, while debugging under Xcode the code currently will return -`false` as Xcode starts the application with `US-ASCII` as encoding, no matter what -encoding is actually used and even setting `LC_ALL` in the product scheme doesn't -change anything. I still need to investigate this. - - -## Differences - -As this implementation is based on existing code from my private helper -classes, it derived some constraints of it. Starting from v1.5.0 most of the -differences between this and the standard C++17/C++20 API where removed. - - -### 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), -[#2936](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2936) and -[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937). -The currently selected behavior (starting from v1.4.0) is following -[#2682](https://wg21.cmeerw.net/lwg/issue2682), [#2936](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2936), -[#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), -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 -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 -error is also advocated by the newer paper -[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revision -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 -([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)). - -### Not Implemented on C++ before C++17 - -```cpp -// methods in ghc::filesystem::path: -path& operator+=(basic_string_view x); -int compare(basic_string_view s) const; -``` - -These are not implemented under C++11 and C++14, as there is no -`std::basic_string_view` available and I did want to keep this -implementation self-contained and not write a full C++17-upgrade for -C++11/14. Starting with v1.1.0 these are supported when compiling -`ghc::filesystem` under C++17 of C++20. - -Starting with v1.5.2 `ghc::filesystem` will try to allow the use of -`std::experimental::basic_string_view` where it detects is availability. -Additionally if you have a `basic_string_view` compatible c++11 -implementation it can be used instead of `std::basic_string_view` -by defining `GHC_HAS_CUSTOM_STRING_VIEW` and importing the -implementation into the `ghc::filesystem` namespace with: - -```cpp -namespace ghc { - namespace filesystem { - using my::basic_string_view; - } -} -``` - -before including the filesystem header. - -### Differences in API - -To not depend on any external third party libraries and still stay portable and -compact, this implementation is following the ["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/) in that all -`std::string` instances will be interpreted the same as `std::u8string` encoding -wise and as being in UTF-8. The `std::u16string` will be seen as UTF-16 and `std::u32string` will be -seen as Unicode codepoints. Depending on the size of `std::wstring` characters, it will handle -`std::wstring` as being UTF-16 (e.g. Windows) or `char32_t` Unicode codepoints -(currently all other platforms). - -#### Differences of Specific Interfaces - -Starting with v1.5.0 `ghc::filesystem` is following the C++17 standard in -using `wchar_t` and `std::wstring` on Windows as the types internally used -for path representation. It is still possible to get the old behavior by defining -`GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE` and get `filesystem::path::string_type` as -`std::string` and `filesystem::path::value_type` as `wchar_t`. - -If you need to call some Windows API, with v1.5.0 and above, simply -use the W-variant of the Windows-API call (e.g. `GetFileAttributesW(p.c_str())`). - -:information_source: **Note:** _When using the old behavior by defining -`GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE`, use the `path::wstring()` member -(e.g. `GetFileAttributesW(p.wstring().c_str())`). This gives you the -Unicode variant independent of the `UNICODE` macro and makes sharing code -between Windows, Linux and macOS easier and works with `std::filesystem` and -`ghc::filesystem`._ - -```cpp -std::string path::u8string() const; -std::string path::generic_u8string() const; -vs. -std::u8string path::u8string() const; -std::u8string path::generic_u8string() const; -``` - -The return type of these two methods is depending on the used C++ standard -and if `GHC_FILESYSTEM_ENFORCE_CPP17_API` is defined. On C++11, C++14 and -C++17 or when `GHC_FILESYSTEM_ENFORCE_CPP17_API` is defined, the return -type is `std::string`, and on C++20 without the define it is `std::u8string`. - -### Differences in Behavior - -I created a wiki entry about quite a lot of [behavioral differences](https://github.com/gulrak/filesystem/wiki/Differences-to-Standard-Filesystem-Implementations) -between different `std::filesystem` implementations that could result in a -mention here, but this readme only tries to address the design choice -differences between `ghc::filesystem` and those. I try to update the wiki page -from time to time. - -Any additional observations are welcome! - -#### fs.path ([ref](https://en.cppreference.com/w/cpp/filesystem/path)) - -Since v1.5.0 the complete inner mechanics of this implementations `fs::path` -where changed to the _native_ format as the internal representation. -Creating any mixed slash `fs::path` object under Windows (e.g. with `"C:\foo/bar"`) -will lead clean path with `"C:\foo\bar"` via `native()` and `"C:/foo/bar"` via -`generic_string()` API. On all platforms redundant additional separators are -removed, even if this is not enforced by the standard and other implementations -mostly not do this. - -Additionally this implementation follows the standards suggestion to handle -posix paths of the form `"//host/path"` and USC path on windows also as having -a root-name (e.g. `"//host"`). The GCC implementation didn't choose to do that -while testing on Ubuntu 18.04 and macOS with GCC 8.1.0 or Clang 7.0.0. This difference -will show as warnings under `std::filesystem`. This leads to a change in the -algorithm described in the standard for `operator/=(path& p)` where any path -`p` with `p.is_absolute()` will degrade to an assignment, while this implementation -has the exception where `*this == *this.root_name()` and `p == preferred_separator` -a normal append will be done, to allow: - -```cpp -fs::path p1 = "//host/foo/bar/file.txt"; -fs::path p2; -for (auto p : p1) p2 /= p; -ASSERT(p1 == p2); -``` - -For all non-host-leading paths the behavior will match the one described by -the standard. - - -## Open Issues - -### Windows - -#### Symbolic Links on Windows - -As symbolic links on Windows, while being supported more or less since -Windows Vista (with some strict security constraints) and fully since some earlier -build of Windows 10, when "Developer Mode" is activated, are at time of writing -(2018) rarely used, still they are supported wiit th this implementation. - -#### Permissions - -The Windows ACL permission feature translates badly to the POSIX permission -bit mask used in the interface of C++17 filesystem. The permissions returned -in the `file_status` are therefore currently synthesized for the `user`-level -and copied to the `group`- and `other`-level. There is still some potential -for more interaction with the Windows permission system, but currently setting -or reading permissions with this implementation will most certainly not lead -to the expected behavior. - - -## Release Notes - -### v1.6.0 (wip) - -* Replaced _travis-ci.org_ with GitHub Workflow for the configurations: - Ubuntu 20.04: GCC 9.3, Ubuntu 18.04: GCC 7.5, GCC 8.4, macOS 10.15: Xcode 12.4, - Windows 10: Visual Studio 2019 - -### [v1.5.8](https://github.com/gulrak/filesystem/releases/tag/v1.5.8) - -* Fix for [#125]((https://github.com/gulrak/filesystem/issues/124), where - `fs::create_directories` on Windows no longer breaks on long filenames. - -### [v1.5.6](https://github.com/gulrak/filesystem/releases/tag/v1.5.6) - -* Fix for [#124](https://github.com/gulrak/filesystem/issues/124), - `ghc::filesystem` treated mounted folder/volumes erroneously as symlinks, - leading `fs::canonical` to fail on paths containing those. -* Fix for [#122](https://github.com/gulrak/filesystem/issues/122), incrementing - the `recursive_directory_iterator` will not try to enter dead symlinks. -* Fix for [#121](https://github.com/gulrak/filesystem/issues/121), on Windows - backend the `fs::remove` failed when the path pointed to a read-only entry, - see also ([microsoft/STL#1511](https://github.com/microsoft/STL/issues/1511)) - for the corresponding issue in `std::fs` on windows. -* Fix for [#119](https://github.com/gulrak/filesystem/issues/119), added missing - support for char16_t and char32_t and on C++20 char8_t literals. -* Pull request [#118](https://github.com/gulrak/filesystem/pull/118), when - running tests as root, disable tests that would not work. -* Pull request [#117](https://github.com/gulrak/filesystem/pull/117), added - checks to tests to detect the clang/libstdc++ combination. -* Fix for [#116](https://github.com/gulrak/filesystem/issues/116), internal - macro `GHC_NO_DIRENT_D_TYPE` allows os detection to support systems without - the `dirent.d_type` member, experimental first QNX compile support as - initial use case, fixed issue with filesystems returning DT_UNKNOWN - (e.g. reiserfs). -* Pull request [#115](https://github.com/gulrak/filesystem/pull/115), added - `string_view` support when clang with libstdc++ is detected. -* Fix for [#114](https://github.com/gulrak/filesystem/issues/114), for macOS - the pre-Catalina deployment target detection worked only if `` - was included before `` or ``/``. -* Fix for [#113](https://github.com/gulrak/filesystem/issues/113), the use of - standard chapter numbers was misleading since C++17 and C++20 `std::filesystem` - features are supported, and was replaced by the tag-like chapter names that - stay (mostly) consistent over the versions. - -### [v1.5.4](https://github.com/gulrak/filesystem/releases/tag/v1.5.4) - -* Pull request [#112](https://github.com/gulrak/filesystem/pull/112), lots - of cleanup work on the readme, thanks! -* Enhancement for [#111](https://github.com/gulrak/filesystem/issues/111), - further optimization of directory iteration, performance for - `recursive_directory_iterator` over large trees now somewhere between - libc++ and libstdc++. -* Enhancement for [#110](https://github.com/gulrak/filesystem/issues/110), - `ghc::filesystem` now has preliminary support for Cygwin. Changes where - made to allow the tests to compile and run successfully (tested with GCC - 10.2.0), feedback and additional PRs welcome as it is currently not - part of the CI configuration. -* Pull request [#109](https://github.com/gulrak/filesystem/pull/109), various - spelling errors in error messages and comments fixed. -* Pull request [#108](https://github.com/gulrak/filesystem/pull/108), old - style casts removed. -* Fix for [#107](https://github.com/gulrak/filesystem/issues/107), the error - handling for status calls was suppressing errors on symlink targets. -* Pull request [#106](https://github.com/gulrak/filesystem/pull/106), fixed - detection of AppleClang for compile options. -* Pull request [#105](https://github.com/gulrak/filesystem/pull/105), added - option `GHC_FILESYSTEM_BUILD_STD_TESTING` to override additional build of - `std::filesystem` versions of the tests for comparison and the possibility - to use `GHC_FILESYSTEM_TEST_COMPILE_FEATURES` to prefill the used compile - features defaulting to `CMAKE_CXX_COMPILE_FEATURES` when not given. - -### [v1.5.2](https://github.com/gulrak/filesystem/releases/tag/v1.5.2) - -* Enhancement [#104](https://github.com/gulrak/filesystem/issues/104), - on POSIX backend: optimized reuse of status information and reduced - `directory_entry` creation leads to about 20%-25% in tests with - `recursive_directory_iterator` over a larger directory tree. -* Pull request [#103](https://github.com/gulrak/filesystem/pull/103), `wchar_t` - was not in the list of supported char types on non-Windows backends. -* Pull request [#102](https://github.com/gulrak/filesystem/pull/102), improved - `string_view` support makes use of `` or `` - when available, and allows use of custom `basic_string_view` implementation - when defining `GHC_HAS_CUSTOM_STRING_VIEW` and importing the string view - into the `ghc::filesystem` namespace before including filesystem header. -* Pull request [#101](https://github.com/gulrak/filesystem/pull/101), fix for - [#100](https://github.com/gulrak/filesystem/issues/100), append and concat - type of operations on path called redundant conversions. -* Pull request [#98](https://github.com/gulrak/filesystem/pull/98), on older - linux variants (GCC 7/8), the comparison `std::filesystem` tests now link - with `-lrt` to avoid issues. -* Fix for [#97](https://github.com/gulrak/filesystem/issues/97), on BTRFS the - test case for `fs::hard_link_count` failed due to the filesystems behavior, - the test case was adapted to take that into account. -* Pull request [#96](https://github.com/gulrak/filesystem/pull/96), the export - attribute defines `GHC_FS_API` and `GHC_FS_API_CLASS` are now honored when when - set from outside to allow override of behavior. -* Fix for [#95](https://github.com/gulrak/filesystem/issues/95), the syntax for - disabling the deprecated warning in tests in MSVC was wrong. -* Pull request [#93](https://github.com/gulrak/filesystem/pull/93), now the - CMake configuration file is configured and part of the `make install` files. - -### [v1.5.0](https://github.com/gulrak/filesystem/releases/tag/v1.5.0) - -* Fix for [#91](https://github.com/gulrak/filesystem/issues/91), the way - the CMake build options `GHC_FILESYSTEM_BUILD_TESTING`, `GHC_FILESYSTEM_BUILD_EXAMPLES` - and `GHC_FILESYSTEM_WITH_INSTALL` where implemented, prohibited setting them - from a parent project when using this via `add_subdirectory`, this fix - allows to set them again. -* Major refactoring for [#90](https://github.com/gulrak/filesystem/issues/90), - the way, the Windows version of `fs::path` was originally created from the - POSIX based implementation was, by adaption of the incoming and outgoing - strings. This resulted in a mutable cache inside `fs::path`on Windows, that - was inherently not thread-safe, even for `const` methods. - To not add additional patches to a suboptimal solution, this time I reworked - the `path` code to now store _native_ path-representation. This changed a - lot of code, but when combined with `wchar_t` as `value_type` helped to avoid - lots of conversion for calls to Win-API.
- As interfaces where changed, it had to be released in a new minor version. - The set of refactorings resulted in the following changes: - * `fs::path::native()` and `fs::path::c_str()` can now be `noexcept` as the - standard mandates - * On Windows `wchar_t` is now the default for `fs::path::value_type` and - `std::wstring` is the default for `fs::path::string_type`. - * This allows the implementation to call Win-API without allocating - conversions - * Thread-safety on `const` methods of `fs::path` is no longer an issue - * Some code could be simplified during this refactoring - * Automatic prefixing of long path on Windows can now be disabled with - defining `GHC_WIN_DISABLE_AUTO_PREFIXES`, for all other types of prefixes - or namespaces the behavior follows that of MSVC `std::filesystem::path` - * In case the old `char`/`std::string` based approach for Windows is still - needed, it can be activated with `GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE` -* Enhancement for [#89](https://github.com/gulrak/filesystem/issues/89), `fs::file_status` - now supports `operator==` introduced in `std::filesystem` with C++20. -* Refactoring for [#88](https://github.com/gulrak/filesystem/issues/88), `fs::path::parent_path()` - had a performance issue, as it was still using a loop based approach to recreate - the parent from elements. This created lots of temporaries and was too slow - especially on long paths. - -### [v1.4.0](https://github.com/gulrak/filesystem/releases/tag/v1.4.0) - -* Enhancements for [#71](https://github.com/gulrak/filesystem/issues/71), when compiled with C++20: - * `char8_t` and `std::u8string` are supported where `Source` is the parameter type - * `fs::path::u8string()` and `fs::path::generic_u8string()` now return a `std::u8string` - * The _spaceship operator_ `<=>` is now supported for `fs::path` - * With the define `GHC_FILESYSTEM_ENFORCE_CPP17_API` `ghc::filesystem` will fall back - to the old `fs::path::u8string()` and `fs::path::generic_u8string()` API if preferred -* Bugfix for `fs::proximate(p, ec)` where the internal call to `fs::current_path()` was not - using the `error_code` variant, throwing possible exceptions instead of setting `ec`. -* Enhancement `LWG_2936_BEHAVIOUR` is now on by default. -* Some cleanup work to reduce preprocessor directives for better readability and remove unneeded - template specializations. - -### [v1.3.10](https://github.com/gulrak/filesystem/releases/tag/v1.3.10) - -* Fix for [#81](https://github.com/gulrak/filesystem/issues/81), fixed issues with - handling `Source` parameters that are string views. -* Fix for [#79](https://github.com/gulrak/filesystem/issues/79), the bit operations - for filesystem bitmasks that should be are now `constexpr`. - -### [v1.3.8](https://github.com/gulrak/filesystem/releases/tag/v1.3.8) - -* Refactoring for [#78](https://github.com/gulrak/filesystem/issues/78), the dynamic - switching helper includes are now using `__MAC_OS_X_VERSION_MIN_REQUIRED` to - ensure that `std::filesystem` is only selected on macOS if the deployment target is - at least Catalina. -* Bugfix for [#77](https://github.com/gulrak/filesystem/issues/77), the `directory_iterator` - and the `recursive_directory_iterator` had an issue with the `skip_permission_denied` - option, that leads to the inability to skip SIP protected folders on macOS. -* Enhancement for [#76](https://github.com/gulrak/filesystem/issues/76), `_MSVC_LANG` is - now used when available, additionally to `__cplusplus`, in the helping headers to - allow them to work even when `/Zc:__cplusplus` is not used. -* Bugfix for [#75](https://github.com/gulrak/filesystem/issues/75), NTFS reparse points - to mapped volumes where handled incorrect, leading to `false` on `fs::exists` or - not-found-errors on `fs::status`. Namespaced paths are not filtered anymore. - -### [v1.3.6](https://github.com/gulrak/filesystem/releases/tag/v1.3.6) - -* Pull request [#74](https://github.com/gulrak/filesystem/pull/74), on Windows symlink - evaluation used the wrong reparse struct information and was not handling the case - of relative paths well, thanks for the contribution. -* Refactoring for [#73](https://github.com/gulrak/filesystem/issues/73), enhanced performance - in path handling. the changes lead to much fewer path/string creations or copies, speeding - up large directory iteration or operations on many path instances. -* Bugfix for [#72](https://github.com/gulrak/filesystem/issues/72), the `TestAllocator` in - `filesystem_test.cpp` was completed to fulfill the requirements to build on CentOS 7 with - `devtoolset-9`. CentOS 7 and CentOS 8 are now part of the CI builds. -* Bugfix for [#70](https://github.com/gulrak/filesystem/issues/70), root names are now case - insensitive on Windows. This fix also adds the new behavior switch `LWG_2936_BEHAVIOUR` - that allows to enable post C++17 `fs::path::compare` behavior, where the comparison is as - if it was an element wise path comparison as described in - [LWG 2936](https://cplusplus.github.io/LWG/issue2936) and C++20 `[fs.path.compare]`. - It is default off in v1.3.6 and will be default starting from v1.4.0 as it changes ordering. - -### [v1.3.4](https://github.com/gulrak/filesystem/releases/tag/v1.3.4) - -* Pull request [#69](https://github.com/gulrak/filesystem/pull/69), use `wchar_t` versions of - `std::fstream` from `ghc::filesystem::fstream` wrappers on Windows if using GCC with libc++. -* Bugfix for [#68](https://github.com/gulrak/filesystem/issues/68), better handling of - permission issues for directory iterators when using `fs::directory_options::skip_permission_denied` - and initial support for compilation with emscripten. -* Refactoring for [#66](https://github.com/gulrak/filesystem/issues/63), unneeded shared_ptr guards - where removed and the file handles closed where needed to avoid unnecessary allocations. -* Bugfix for [#63](https://github.com/gulrak/filesystem/issues/63), fixed issues on Windows - with clang++ and C++17. -* Pull request [#62](https://github.com/gulrak/filesystem/pull/62), various fixes for - better Android support, thanks for the PR -* Pull request [#61](https://github.com/gulrak/filesystem/pull/61), `ghc::filesystem` now - supports use in projects with disabled exceptions. API signatures using exceptions for - error handling are not available in this mode, thanks for the PR (this resolves - [#60](https://github.com/gulrak/filesystem/issues/60) and - [#43](https://github.com/gulrak/filesystem/issues/43)) - -### [v1.3.2](https://github.com/gulrak/filesystem/releases/tag/v1.3.2) - -* Bugfix for [#58](https://github.com/gulrak/filesystem/issues/58), on MinGW the - compilation could fail with an error about an undefined `ERROR_FILE_TOO_LARGE` - constant. -* Bugfix for [#56](https://github.com/gulrak/filesystem/issues/58), `fs::lexically_relative` - didn't ignore trailing slash on the base parameter, thanks for PR - [#57](https://github.com/gulrak/filesystem/pull/57). -* Bugfix for [#55](https://github.com/gulrak/filesystem/issues/55), `fs::create_directories` - returned `true` when nothing needed to be created, because the directory already existed. -* Bugfix for [#54](https://github.com/gulrak/filesystem/issues/54), `error_code` - was not reset, if cached result was returned. -* Pull request [#53](https://github.com/gulrak/filesystem/pull/53), fix for wrong - handling of leading whitespace when reading `fs::path` from a stream. -* Pull request [#52](https://github.com/gulrak/filesystem/pull/52), an ARM Linux - target is now part of the CI infrastructure with the service of Drone CI. -* Pull request [#51](https://github.com/gulrak/filesystem/pull/51), FreeBSD is now - part of the CI infrastructure with the service of Cirrus CI. -* Pull request [#50](https://github.com/gulrak/filesystem/pull/50), adaptive cast to - `timespec` fields to avoid warnings. - -### [v1.3.0](https://github.com/gulrak/filesystem/releases/tag/v1.3.0) - -* **Important: `ghc::filesystem` is re-licensed from BSD-3-Clause to MIT license.** (see - [#47](https://github.com/gulrak/filesystem/issues/47)) -* Pull request [#46](https://github.com/gulrak/filesystem/pull/46), suppresses - unused parameter warning on Android. -* Bugfix for [#44](https://github.com/gulrak/filesystem/issues/44), fixes - for warnings from newer Xcode versions. - -### [v1.2.10](https://github.com/gulrak/filesystem/releases/tag/v1.2.10) - -* The Visual Studio 2019 compiler, GCC 9.2 and Clang 9.0 where added to the - CI configuration. -* Bugfix for [#41](https://github.com/gulrak/filesystem/issues/41), `fs::rename` - on Windows didn't replace an existing regular file as required by the standard, - but gave an error. New tests and a fix as provided in the issue was implemented. -* Bugfix for [#39](https://github.com/gulrak/filesystem/issues/39), for the - forwarding use via `fs_fwd.hpp` or `fs_std_fwd.hpp` there was a use of - `DWORD` in the forwarding part leading to an error if `Windows.h` was not - included before the header. The tests were changed to give an error in that - case too and the useage of `DWORD` was removed. -* Bugfix for [#38](https://github.com/gulrak/filesystem/issues/38), casting the - return value of `GetProcAddress` gave a warning with `-Wcast-function-type` - on MSYS2 and MinGW GCC 9 builds. - -### [v1.2.8](https://github.com/gulrak/filesystem/releases/tag/v1.2.8) - -* Pull request [#30](https://github.com/gulrak/filesystem/pull/30), the - `CMakeLists.txt` will automatically exclude building examples and tests when - used as submodule, the configuration options now use a prefixed name to - reduce risk of conflicts. -* Pull request [#24](https://github.com/gulrak/filesystem/pull/24), install - target now creates a `ghcFilesystemConfig.cmake` in - `${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem` for `find_package` that - exports a target as `ghcFilesystem::ghc_filesystem`. -* Pull request [#31](https://github.com/gulrak/filesystem/pull/31), fixes - `error: redundant redeclaration of 'constexpr' static data member` deprecation - warning in C++17 mode. -* Pull request [#32](https://github.com/gulrak/filesystem/pull/32), fixes - old-style-cast warnings. -* Pull request [#34](https://github.com/gulrak/filesystem/pull/34), fixes - [TOCTOU](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use) situation - on `fs::create_directories`, thanks for the PR! -* Feature [#35](https://github.com/gulrak/filesystem/issues/35), new CMake - option to add an install target `GHC_FILESYSTEM_WITH_INSTALL` that is - defaulted to OFF if `ghc::filesystem` is used via `add_subdirectory`. -* Bugfix for [#33](https://github.com/gulrak/filesystem/issues/33), fixes - an issue with `fs::path::lexically_normal()` that leaves a trailing separator - in case of a resulting path ending with `..` as last element. -* Bugfix for [#36](https://github.com/gulrak/filesystem/issues/36), warnings - on Xcode 11.2 due to unhelpful references in path element iteration. - -### [v1.2.6](https://github.com/gulrak/filesystem/releases/tag/v1.2.6) - -* Pull request [#23](https://github.com/gulrak/filesystem/pull/23), tests and - examples can now be disabled in CMake via setting `BUILD_TESTING` and - `BUILD_EXAMPLES` to `NO`, `OFF` or `FALSE`. -* Pull request [#25](https://github.com/gulrak/filesystem/pull/25), - missing specialization for construction from `std::string_view` when - available was added. -* Additional test case when `std::string_view` is available. -* Bugfix for [#27](https://github.com/gulrak/filesystem/issues/27), the - `fs::path::preferred_separator` declaration was not compiling on pre - C++17 compilers and no test accessed it, to show the problem. Fixed - it to an construction C++11 compiler should accept and added a test that - is successful on all combinations tested. -* Bugfix for [#29](https://github.com/gulrak/filesystem/issues/29), stricter - warning settings where chosen and resulting warnings where fixed. - -### [v1.2.4](https://github.com/gulrak/filesystem/releases/tag/v1.2.4) - -* Enabled stronger warning switches and resulting fixed issues on GCC and MinGW -* Bugfix for #22, the `fs::copy_options` where not forwarded from `fs::copy` to - `fs::copy_file` in one of the cases. - -### [v1.2.2](https://github.com/gulrak/filesystem/releases/tag/v1.2.2) - -* Fix for ([#21](https://github.com/gulrak/filesystem/pull/21)), when compiling - on Alpine Linux with musl instead of glibc, the wrong `strerror_r` signature - was expected. The complex preprocessor define mix was dropped in favor of - the usual dispatch by overloading a unifying wrapper. - -### [v1.2.0](https://github.com/gulrak/filesystem/releases/tag/v1.2.0) - -* Added MinGW 32/64 and Visual Studio 2015 builds to the CI configuration. -* Fixed additional compilation issues on MinGW. -* Pull request ([#13](https://github.com/gulrak/filesystem/pull/13)), set - minimum required CMake version to 3.7.2 (as in Debian 8). -* Pull request ([#14](https://github.com/gulrak/filesystem/pull/14)), added - support for a make install target. -* Bugfix for ([#15](https://github.com/gulrak/filesystem/issues/15)), the - forward/impl way of using `ghc::filesystem` missed a `` include - in the windows case. -* Bugfix for ([#16](https://github.com/gulrak/filesystem/issues/16)), - VS2019 didn't like the old size dispatching in the utf8 decoder, so it - was changed to a sfinae based approach. -* New feature ([#17](https://github.com/gulrak/filesystem/issues/17)), optional - support for standard conforming `wchar_t/std::wstring` interface when - compiling on Windows with defined `GHC_WIN_WSTRING_STRING_TYPE`, this is - default when using the `ghc/fs_std*.hpp` header, to enhance compatibility. -* New feature ([#18](https://github.com/gulrak/filesystem/issues/18)), optional - filesystem exceptions/errors on Unicode errors with defined - `GHC_RAISE_UNICODE_ERRORS` (instead of replacing invalid code points or - UTF-8 encoding errors with the replacement character `U+FFFD`). -* Pull request ([#20](https://github.com/gulrak/filesystem/pull/20)), fix for - file handle leak in `fs::copy_file`. -* Coverage now checked in CI (~95% line coverage). - -### [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 deprecated, 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 behavior 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) - -* Restructuring of the project directory. The header files are now using - `hpp` as extension to be marked as c++ and they where moved to - `include/ghc/` to be able to include by `` as the - former include name might have been to generic and conflict with other - files. -* Better CMake support: `ghc::filesystem` now can be used as a submodul - and added with `add_subdirectory` and will export itself as `ghc_filesystem` - target. To use it, only `target_link_libraries(your-target ghc_filesystem)` - is needed and the include directories will be set so `#include ` - will be a valid directive. - Still you can simply only add the header file to you project and include it - from there. -* Enhancement ([#10](https://github.com/gulrak/filesystem/issues/10)), - support for separation of implementation and forwarded api: Two - additional simple includes are added, that can be used to forward - `ghc::filesystem` declarations (`fs_fwd.hpp`) and to wrap the - implementation into a single cpp (`fs_impl.hpp`) -* The `std::basic_string_view` variants of the `fs::path` api are - now supported when compiling with C++17. -* Added CI integration for Travis-CI and Appveyor. -* Fixed MinGW compilation issues. -* Added long filename support for Windows. - -### [v1.0.10](https://github.com/gulrak/filesystem/releases/tag/v1.0.10) - -* Bugfix for ([#9](https://github.com/gulrak/filesystem/issues/9)), added - missing return statement to `ghc::filesystem::path::generic_string()` -* Added checks to hopefully better compile against Android NDK. There where - no tests run yet, so feedback is needed to actually call this supported. -* `filesystem.h` was renamed `filesystem.hpp` to better reflect that it is - a c++ language header. - -### [v1.0.8](https://github.com/gulrak/filesystem/releases/tag/v1.0.8) - -* Bugfix for ([#6](https://github.com/gulrak/filesystem/issues/6)), where - `ghc::filesystem::remove()` and `ghc::filesystem::remove_all()` both are - now able to remove a single file and both will not raise an error if the - path doesn't exist. -* Merged pull request ([#7](https://github.com/gulrak/filesystem/pull/7)), - a typo leading to setting error code instead of comparing it in - `ghc::filesystem::remove()` under Windows. -* Bugfix for (([#8](https://github.com/gulrak/filesystem/issues/8)), the - Windows version of `ghc::filesystem::directory_iterator` now releases - resources when reaching `end()` like the POSIX one does. - - -### [v1.0.6](https://github.com/gulrak/filesystem/releases/tag/v1.0.6) - -* Bugfix for ([#4](https://github.com/gulrak/filesystem/issues/4)), missing error_code - propagation in `ghc::filesystem::copy()` and `ghc::filesystem::remove_all` fixed. -* Bugfix for ([#5](https://github.com/gulrak/filesystem/issues/5)), added missing std - namespace in `ghc::filesystem::recursive_directory_iterator::difference_type`. - -### [v1.0.4](https://github.com/gulrak/filesystem/releases/tag/v1.0.4) - -* Bugfix for ([#3](https://github.com/gulrak/filesystem/issues/3)), fixed missing inlines - and added test to ensure including into multiple implementation files works as expected. -* Building tests with `-Wall -Wextra -Werror` and fixed resulting issues. - -### [v1.0.2](https://github.com/gulrak/filesystem/releases/tag/v1.0.2) - -* Updated catch2 to v2.4.0. -* Refactored `fs.op.permissions` test to work with all tested `std::filesystem` - implementations (gcc, clang, msvc++). -* Added helper class `ghc::filesystem::u8arguments` as `argv` converter, to - help follow the UTF-8 path on windows. Simply instantiate it with `argc` and - `argv` and it will fetch the Unicode version of the command line and convert - it to UTF-8. The destructor reverts the change. -* Added `examples` folder with hopefully some usefull example usage. Examples are - tested (and build) with `ghc::filesystem` and C++17 `std::filesystem` when - available. -* Starting with this version, only even patch level versions will be tagged and - odd patch levels mark in-between non-stable wip states. -* Tests can now also be run against MS version of `std::filesystem` for comparison. -* Added missing `fstream` include. -* Removed non-conforming C99 `timespec`/`timeval` usage. -* Fixed some integer type mismatches that could lead to warnings. -* Fixed `chrono` conversion issues in test and example on clang 7.0.0. - -### [v1.0.1](https://github.com/gulrak/filesystem/releases/tag/v1.0.1) - -* Bugfix: `ghc::filesystem::canonical` now sees empty path as non-existant and reports - an error. Due to this `ghc::filesystem::weakly_canonical` now returns relative - paths for non-existant argument paths. ([#1](https://github.com/gulrak/filesystem/issues/1)) -* Bugfix: `ghc::filesystem::remove_all` now also counts directories removed ([#2](https://github.com/gulrak/filesystem/issues/2)) -* Bugfix: `recursive_directory_iterator` tests didn't respect equality domain issues - and dereferencapable constraints, leading to fails on `std::filesystem` tests. -* Bugfix: Some `noexcept` tagged methods and functions could indirectly throw exceptions - due to UFT-8 decoding issues. -* `std_filesystem_test` is now also generated if LLVM/clang 7.0.0 is found. - - -### [v1.0.0](https://github.com/gulrak/filesystem/releases/tag/v1.0.0) - -This was the first public release version. It implements the full range of -C++17 `std::filesystem`, as far as possible without other C++17 dependencies. - diff --git a/vendor/FileSystem/cmake/GhcHelper.cmake b/vendor/FileSystem/cmake/GhcHelper.cmake deleted file mode 100644 index 8fffae9f..00000000 --- a/vendor/FileSystem/cmake/GhcHelper.cmake +++ /dev/null @@ -1,64 +0,0 @@ -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 (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) - if(APPLE) - target_link_libraries(${targetName} -lc++fs) - else() - target_compile_options(${targetName} PRIVATE "-stdlib=libc++") - target_link_libraries(${targetName} -stdlib=libc++ -lc++fs $<$:rt>) - endif() - else() - if(NOT APPLE) - target_compile_options(${targetName} PRIVATE "-stdlib=libc++") - target_link_libraries(${targetName} -stdlib=libc++) - endif() - endif() - 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) - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) - target_link_libraries(${targetName} -lstdc++fs) - endif() - target_compile_options(${targetName} PRIVATE $<$:-Wa,-mbig-obj>) - 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() - -macro(AddTestExecutableWithStdCpp cppStd) - add_executable(filesystem_test_cpp${cppStd} ${ARGN}) - set_property(TARGET filesystem_test_cpp${cppStd} PROPERTY CXX_STANDARD ${cppStd}) - target_link_libraries(filesystem_test_cpp${cppStd} ghc_filesystem) - target_compile_options(filesystem_test_cpp${cppStd} PRIVATE - $<$:-s DISABLE_EXCEPTION_CATCHING=0> - $<$,$>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-error=deprecated-declarations> - $<$:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror -Wno-error=deprecated-declarations> - $<$:/WX /wd4996> - $<$:-Wa,-mbig-obj> - $<$:--coverage>) - if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) - target_compile_definitions(filesystem_test_cpp${cppStd} PRIVATE _CRT_SECURE_NO_WARNINGS) - endif() - if(EMSCRIPTEN) - set_target_properties(filesystem_test_cpp${cppStd} PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1") - endif() - ParseAndAddCatchTests(filesystem_test_cpp${cppStd}) -endmacro() diff --git a/vendor/FileSystem/cmake/config.cmake.in b/vendor/FileSystem/cmake/config.cmake.in deleted file mode 100644 index ace97616..00000000 --- a/vendor/FileSystem/cmake/config.cmake.in +++ /dev/null @@ -1,6 +0,0 @@ -@PACKAGE_INIT@ - -# import targets -include("${CMAKE_CURRENT_LIST_DIR}/ghc_filesystem-targets.cmake") - -check_required_components(ghcfilesystem) \ No newline at end of file diff --git a/vendor/FileSystem/examples/CMakeLists.txt b/vendor/FileSystem/examples/CMakeLists.txt deleted file mode 100644 index 17bb3d63..00000000 --- a/vendor/FileSystem/examples/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ - -add_executable(fs_dir dir.cpp) -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) - -add_executable(fs_du du.cpp) -target_link_libraries(fs_du ghc_filesystem) -AddExecutableWithStdFS(std_fs_du du.cpp) - -if(EXISTS "${PROJECT_SOURCE_DIR}/examples/benchmark.cpp") - add_executable(fs_benchmark benchmark.cpp) - set_property(TARGET fs_benchmark PROPERTY CXX_STANDARD 17) - target_link_libraries(fs_benchmark ghc_filesystem) -endif() \ No newline at end of file diff --git a/vendor/FileSystem/examples/dir.cpp b/vendor/FileSystem/examples/dir.cpp deleted file mode 100644 index abd4cc68..00000000 --- a/vendor/FileSystem/examples/dir.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) -#if __has_include() -#define GHC_USE_STD_FS -#include -namespace fs = std::filesystem; -#endif -#endif -#ifndef GHC_USE_STD_FS -#include -namespace fs = ghc::filesystem; -#endif - -template -std::time_t to_time_t(TP tp) -{ - // Based on trick from: Nico Josuttis, C++17 - The Complete Guide - std::chrono::system_clock::duration dt = std::chrono::duration_cast(tp - TP::clock::now()); - return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now() + dt); -} - -static std::string perm_to_str(fs::perms prms) -{ - std::string result; - result.reserve(9); - for (int i = 0; i < 9; ++i) { - result = ((static_cast(prms) & (1 << i)) ? "xwrxwrxwr"[i] : '-') + result; - } - return result; -} - -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: dir " << std::endl; - exit(1); - } - fs::path dir{"."}; - if (argc == 2) { - dir = fs::u8path(argv[1]); - } - for (auto de : fs::directory_iterator(dir)) { - auto ft = to_time_t(de.last_write_time()); - auto ftm = *std::localtime(&ft); - std::cout << (de.is_directory() ? "d" : "-") << perm_to_str(de.symlink_status().permissions()) << " " << std::setw(8) << (de.is_directory() ? "-" : std::to_string(de.file_size())) << " " << std::put_time(&ftm, "%Y-%m-%d %H:%M:%S") << " " - << de.path().filename().string() << std::endl; - } - return 0; -} diff --git a/vendor/FileSystem/examples/du.cpp b/vendor/FileSystem/examples/du.cpp deleted file mode 100644 index 929b809a..00000000 --- a/vendor/FileSystem/examples/du.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include - -#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) -#if __has_include() -#define GHC_USE_STD_FS -#include -namespace fs = std::filesystem; -#endif -#endif -#ifndef GHC_USE_STD_FS -#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 << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl; - return 0; -} diff --git a/vendor/FileSystem/include/ghc/filesystem.hpp b/vendor/FileSystem/include/ghc/filesystem.hpp deleted file mode 100644 index 2c7538bc..00000000 --- a/vendor/FileSystem/include/ghc/filesystem.hpp +++ /dev/null @@ -1,5944 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17/C++20 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -// -// To dynamically select std::filesystem where available on most platforms, -// you could use: -// -// #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -// #if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -// #define GHC_USE_STD_FS -// #include -// namespace fs = std::filesystem; -// #endif -// #endif -// #ifndef GHC_USE_STD_FS -// #include -// namespace fs = ghc::filesystem; -// #endif -// -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_H -#define GHC_FILESYSTEM_H - -// #define BSD manifest constant only in -// sys/param.h -#ifndef _WIN32 -#include -#endif - -#ifndef GHC_OS_DETECTED -#if defined(__APPLE__) && defined(__MACH__) -#define GHC_OS_MACOS -#elif defined(__linux__) -#define GHC_OS_LINUX -#if defined(__ANDROID__) -#define GHC_OS_ANDROID -#endif -#elif defined(_WIN64) -#define GHC_OS_WINDOWS -#define GHC_OS_WIN64 -#elif defined(_WIN32) -#define GHC_OS_WINDOWS -#define GHC_OS_WIN32 -#elif defined(__CYGWIN__) -#define GHC_OS_CYGWIN -#elif defined(__svr4__) -#define GHC_OS_SYS5R4 -#elif defined(BSD) -#define GHC_OS_BSD -#elif defined(__EMSCRIPTEN__) -#define GHC_OS_WEB -#include -#elif defined(__QNX__) -#define GHC_OS_QNX -#define GHC_NO_DIRENT_D_TYPE -#else -#error "Operating system currently not supported!" -#endif -#define GHC_OS_DETECTED -#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#if _MSVC_LANG == 201703L -#define GHC_FILESYSTEM_RUNNING_CPP17 -#else -#define GHC_FILESYSTEM_RUNNING_CPP20 -#endif -#elif (defined(__cplusplus) && __cplusplus >= 201703L) -#if __cplusplus == 201703L -#define GHC_FILESYSTEM_RUNNING_CPP17 -#else -#define GHC_FILESYSTEM_RUNNING_CPP20 -#endif -#endif -#endif - -#if defined(GHC_FILESYSTEM_IMPLEMENTATION) -#define GHC_EXPAND_IMPL -#define GHC_INLINE -#ifdef GHC_OS_WINDOWS -#ifndef GHC_FS_API -#define GHC_FS_API -#endif -#ifndef GHC_FS_API_CLASS -#define GHC_FS_API_CLASS -#endif -#else -#ifndef GHC_FS_API -#define GHC_FS_API __attribute__((visibility("default"))) -#endif -#ifndef GHC_FS_API_CLASS -#define GHC_FS_API_CLASS __attribute__((visibility("default"))) -#endif -#endif -#elif defined(GHC_FILESYSTEM_FWD) -#define GHC_INLINE -#ifdef GHC_OS_WINDOWS -#ifndef GHC_FS_API -#define GHC_FS_API extern -#endif -#ifndef GHC_FS_API_CLASS -#define GHC_FS_API_CLASS -#endif -#else -#ifndef GHC_FS_API -#define GHC_FS_API extern -#endif -#ifndef GHC_FS_API_CLASS -#define GHC_FS_API_CLASS -#endif -#endif -#else -#define GHC_EXPAND_IMPL -#define GHC_INLINE inline -#ifndef GHC_FS_API -#define GHC_FS_API -#endif -#ifndef GHC_FS_API_CLASS -#define GHC_FS_API_CLASS -#endif -#endif - -#ifdef GHC_EXPAND_IMPL - -#ifdef GHC_OS_WINDOWS -#include -// additional includes -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef GHC_OS_ANDROID -#include -#if __ANDROID_API__ < 12 -#include -#endif -#include -#define statvfs statfs -#else -#include -#endif -#ifdef GHC_OS_CYGWIN -#include -#endif -#if !defined(__ANDROID__) || __ANDROID_API__ >= 26 -#include -#endif -#endif -#ifdef GHC_OS_MACOS -#include -#endif - -#if defined(__cpp_impl_three_way_comparison) && defined(__has_include) -#if __has_include() -#define GHC_HAS_THREEWAY_COMP -#include -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#else // GHC_EXPAND_IMPL - -#if defined(__cpp_impl_three_way_comparison) && defined(__has_include) -#if __has_include() -#define GHC_HAS_THREEWAY_COMP -#include -#endif -#endif -#include -#include -#include -#include -#include -#include -#include -#ifdef GHC_OS_WINDOWS -#include -#endif -#endif // GHC_EXPAND_IMPL - -// After standard library includes. -// Standard library support for std::string_view. -#if defined(__cpp_lib_string_view) -#define GHC_HAS_STD_STRING_VIEW -#elif defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 4000) && (__cplusplus >= 201402) -#define GHC_HAS_STD_STRING_VIEW -#elif defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 7) && (__cplusplus >= 201703) -#define GHC_HAS_STD_STRING_VIEW -#elif defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) -#define GHC_HAS_STD_STRING_VIEW -#endif - -// Standard library support for std::experimental::string_view. -#if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 3700 && _LIBCPP_VERSION < 7000) && (__cplusplus >= 201402) -#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW -#elif defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)) && (__cplusplus >= 201402) -#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW -#elif defined(__GLIBCXX__) && defined(_GLIBCXX_USE_DUAL_ABI) && (__cplusplus >= 201402) -// macro _GLIBCXX_USE_DUAL_ABI is always defined in libstdc++ from gcc-5 and newer -#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW -#endif - -#if defined(GHC_HAS_STD_STRING_VIEW) -#include -#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) -#include -#endif - -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Enforce C++17 API where possible when compiling for C++20, handles the following cases: -// * fs::path::u8string() returns std::string instead of std::u8string -// #define GHC_FILESYSTEM_ENFORCE_CPP17_API -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// 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 superseded by P1164R1, so only activate if really needed -// #define LWG_2935_BEHAVIOUR -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// LWG #2936 enables new element wise (more expensive) path comparison -// * if this->root_name().native().compare(p.root_name().native()) != 0 return result -// * if this->has_root_directory() and !p.has_root_directory() return -1 -// * if !this->has_root_directory() and p.has_root_directory() return -1 -// * else result of element wise comparison of path iteration where first comparison is != 0 or 0 -// if all comparisons are 0 (on Windows this implementation does case insensitive root_name() -// comparison) -#define LWG_2936_BEHAVIOUR -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) -#define LWG_2937_BEHAVIOUR -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the windows -// version defaults to std::wstring storage backend. Still all std::string will be interpreted -// as UTF-8 encoded. With this define you can enfoce the old behavior on Windows, using -// std::string as backend and for fs::path::native() and char for fs::path::c_str(). This -// needs more conversions so it is (an was before v1.5) slower, bot might help keeping source -// homogeneous in a multi platform project. -// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found, -// instead of replacing them with the unicode replacement character (U+FFFD). -// #define GHC_RAISE_UNICODE_ERRORS -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Automatic prefix windows path with "\\?\" if they would break the MAX_PATH length. -// instead of replacing them with the unicode replacement character (U+FFFD). -#ifndef GHC_WIN_DISABLE_AUTO_PREFIXES -#define GHC_WIN_AUTO_PREFIX_LONG_PATH -#endif // GHC_WIN_DISABLE_AUTO_PREFIXES -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) -#define GHC_FILESYSTEM_VERSION 10509L - -#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) -#define GHC_WITH_EXCEPTIONS -#endif -#if !defined(GHC_WITH_EXCEPTIONS) && defined(GHC_RAISE_UNICODE_ERRORS) -#error "Can't raise unicode errors with exception support disabled" -#endif - -namespace ghc { -namespace filesystem { - -#if defined(GHC_HAS_CUSTOM_STRING_VIEW) -#define GHC_WITH_STRING_VIEW -#elif defined(GHC_HAS_STD_STRING_VIEW) -#define GHC_WITH_STRING_VIEW -using std::basic_string_view; -#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) -#define GHC_WITH_STRING_VIEW -using std::experimental::basic_string_view; -#endif - -// temporary existing exception type for yet unimplemented parts -class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error -{ -public: - not_implemented_exception() - : std::logic_error("function not implemented yet.") - { - } -}; - -template -class path_helper_base -{ -public: - using value_type = char_type; -#ifdef GHC_OS_WINDOWS - static constexpr value_type preferred_separator = '\\'; -#else - static constexpr value_type preferred_separator = '/'; -#endif -}; - -#if __cplusplus < 201703L -template -constexpr char_type path_helper_base::preferred_separator; -#endif - -#ifdef GHC_OS_WINDOWS -class path; -namespace detail { -bool has_executable_extension(const path& p); -} -#endif - -// [fs.class.path] class path -class GHC_FS_API_CLASS path -#if defined(GHC_OS_WINDOWS) && !defined(GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE) -#define GHC_USE_WCHAR_T -#define GHC_NATIVEWP(p) p.c_str() -#define GHC_PLATFORM_LITERAL(str) L##str - : private path_helper_base -{ -public: - using path_helper_base::value_type; -#else -#define GHC_NATIVEWP(p) p.wstring().c_str() -#define GHC_PLATFORM_LITERAL(str) str - : private path_helper_base -{ -public: - using path_helper_base::value_type; -#endif - using string_type = std::basic_string; - using path_helper_base::preferred_separator; - - // [fs.enum.path.format] enumeration format - /// The path format in which the constructor argument is given. - enum format { - generic_format, ///< The generic format, internally used by - ///< ghc::filesystem::path with slashes - native_format, ///< The format native to the current platform this code - ///< is build for - auto_format, ///< Try to auto-detect the format, fallback to native - }; - - template - struct _is_basic_string : std::false_type - { - }; - template - struct _is_basic_string> : std::true_type - { - }; - template - struct _is_basic_string, std::allocator>> : std::true_type - { - }; -#ifdef GHC_WITH_STRING_VIEW - template - struct _is_basic_string> : std::true_type - { - }; - template - struct _is_basic_string>> : std::true_type - { - }; -#endif - - template - using path_type = typename std::enable_if::value, path>::type; - template -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - using path_from_string = - typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || - std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || - std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || - std::is_same::type>::value, - path>::type; - template - using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; -#else - using path_from_string = typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || - std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || - std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value, - path>::type; - template - using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; -#endif - // [fs.path.construct] constructors and destructor - path() noexcept; - path(const path& p); - path(path&& p) noexcept; - path(string_type&& source, format fmt = auto_format); - template > - path(const Source& source, format fmt = auto_format); - template - path(InputIterator first, InputIterator last, format fmt = auto_format); -#ifdef GHC_WITH_EXCEPTIONS - template > - path(const Source& source, const std::locale& loc, format fmt = auto_format); - template - path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format); -#endif - ~path(); - - // [fs.path.assign] assignments - path& operator=(const path& p); - path& operator=(path&& p) noexcept; - path& operator=(string_type&& source); - path& assign(string_type&& source); - template - path& operator=(const Source& source); - template - path& assign(const Source& source); - template - path& assign(InputIterator first, InputIterator last); - - // [fs.path.append] appends - path& operator/=(const path& p); - template - path& operator/=(const Source& source); - template - path& append(const Source& source); - template - path& append(InputIterator first, InputIterator last); - - // [fs.path.concat] concatenation - path& operator+=(const path& x); - path& operator+=(const string_type& x); -#ifdef GHC_WITH_STRING_VIEW - path& operator+=(basic_string_view x); -#endif - path& operator+=(const value_type* x); - path& operator+=(value_type x); - template - path_from_string& operator+=(const Source& x); - template - path_type_EcharT& operator+=(EcharT x); - template - path& concat(const Source& x); - template - path& concat(InputIterator first, InputIterator last); - - // [fs.path.modifiers] modifiers - void clear() noexcept; - path& make_preferred(); - path& remove_filename(); - path& replace_filename(const path& replacement); - path& replace_extension(const path& replacement = path()); - void swap(path& rhs) noexcept; - - // [fs.path.native.obs] native format observers - const string_type& native() const noexcept; - const value_type* c_str() const noexcept; - operator string_type() const; - template , class Allocator = std::allocator> - std::basic_string string(const Allocator& a = Allocator()) const; - std::string string() const; - std::wstring wstring() const; -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - std::u8string u8string() const; -#else - std::string u8string() const; -#endif - std::u16string u16string() const; - std::u32string u32string() const; - - // [fs.path.generic.obs] generic format observers - template , class Allocator = std::allocator> - std::basic_string generic_string(const Allocator& a = Allocator()) const; - std::string generic_string() const; - std::wstring generic_wstring() const; -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - std::u8string generic_u8string() const; -#else - std::string generic_u8string() const; -#endif - std::u16string generic_u16string() const; - std::u32string generic_u32string() const; - - // [fs.path.compare] compare - int compare(const path& p) const noexcept; - int compare(const string_type& s) const; -#ifdef GHC_WITH_STRING_VIEW - int compare(basic_string_view s) const; -#endif - int compare(const value_type* s) const; - - // [fs.path.decompose] decomposition - path root_name() const; - path root_directory() const; - path root_path() const; - path relative_path() const; - path parent_path() const; - path filename() const; - path stem() const; - path extension() const; - - // [fs.path.query] query - bool empty() const noexcept; - bool has_root_name() const; - bool has_root_directory() const; - bool has_root_path() const; - bool has_relative_path() const; - bool has_parent_path() const; - bool has_filename() const; - bool has_stem() const; - bool has_extension() const; - bool is_absolute() const; - bool is_relative() const; - - // [fs.path.gen] generation - path lexically_normal() const; - path lexically_relative(const path& base) const; - path lexically_proximate(const path& base) const; - - // [fs.path.itr] iterators - class iterator; - using const_iterator = iterator; - iterator begin() const; - iterator end() const; - -private: - using impl_value_type = value_type; - using impl_string_type = std::basic_string; - friend class directory_iterator; - void append_name(const value_type* name); - static constexpr impl_value_type generic_separator = '/'; - template - class input_iterator_range - { - public: - typedef InputIterator iterator; - typedef InputIterator const_iterator; - typedef typename InputIterator::difference_type difference_type; - - input_iterator_range(const InputIterator& first, const InputIterator& last) - : _first(first) - , _last(last) - { - } - - InputIterator begin() const { return _first; } - InputIterator end() const { return _last; } - - private: - InputIterator _first; - InputIterator _last; - }; - friend void swap(path& lhs, path& rhs) noexcept; - friend size_t hash_value(const path& p) noexcept; - friend path canonical(const path& p, std::error_code& ec); - friend bool create_directories(const path& p, std::error_code& ec) noexcept; - string_type::size_type root_name_length() const noexcept; - void postprocess_path_with_format(format fmt); - void check_long_path(); - impl_string_type _path; -#ifdef GHC_OS_WINDOWS - void handle_prefixes(); - friend bool detail::has_executable_extension(const path& p); -#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH - string_type::size_type _prefixLength{0}; -#else // GHC_WIN_AUTO_PREFIX_LONG_PATH - static const string_type::size_type _prefixLength{0}; -#endif // GHC_WIN_AUTO_PREFIX_LONG_PATH -#else - static const string_type::size_type _prefixLength{0}; -#endif -}; - -// [fs.path.nonmember] path non-member functions -GHC_FS_API void swap(path& lhs, path& rhs) noexcept; -GHC_FS_API size_t hash_value(const path& p) noexcept; -#ifdef GHC_HAS_THREEWAY_COMP -GHC_FS_API std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept; -#endif -GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept; -GHC_FS_API path operator/(const path& lhs, const path& rhs); - -// [fs.path.io] path inserter and extractor -template -std::basic_ostream& operator<<(std::basic_ostream& os, const path& p); -template -std::basic_istream& operator>>(std::basic_istream& is, path& p); - -// [pfs.path.factory] path factory functions -template > -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) -[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] -#endif -path u8path(const Source& source); -template -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) -[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] -#endif -path u8path(InputIterator first, InputIterator last); - -// [fs.class.filesystem_error] class filesystem_error -class GHC_FS_API_CLASS filesystem_error : public std::system_error -{ -public: - filesystem_error(const std::string& what_arg, std::error_code ec); - filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec); - filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec); - const path& path1() const noexcept; - const path& path2() const noexcept; - const char* what() const noexcept override; - -private: - std::string _what_arg; - std::error_code _ec; - path _p1, _p2; -}; - -class GHC_FS_API_CLASS path::iterator -{ -public: - using value_type = const path; - using difference_type = std::ptrdiff_t; - using pointer = const path*; - using reference = const path&; - using iterator_category = std::bidirectional_iterator_tag; - - iterator(); - iterator(const path& p, const impl_string_type::const_iterator& pos); - iterator& operator++(); - iterator operator++(int); - iterator& operator--(); - iterator operator--(int); - bool operator==(const iterator& other) const; - bool operator!=(const iterator& other) const; - reference operator*() const; - pointer operator->() const; - -private: - friend class path; - impl_string_type::const_iterator increment(const impl_string_type::const_iterator& pos) const; - impl_string_type::const_iterator decrement(const impl_string_type::const_iterator& pos) const; - void updateCurrent(); - impl_string_type::const_iterator _first; - impl_string_type::const_iterator _last; - impl_string_type::const_iterator _prefix; - impl_string_type::const_iterator _root; - impl_string_type::const_iterator _iter; - path _current; -}; - -struct space_info -{ - uintmax_t capacity; - uintmax_t free; - uintmax_t available; -}; - -// [fs.enum] enumerations -// [fs.enum.file_type] -enum class file_type { - none, - not_found, - regular, - directory, - symlink, - block, - character, - fifo, - socket, - unknown, -}; - -// [fs.enum.perms] -enum class perms : uint16_t { - none = 0, - - owner_read = 0400, - owner_write = 0200, - owner_exec = 0100, - owner_all = 0700, - - group_read = 040, - group_write = 020, - group_exec = 010, - group_all = 070, - - others_read = 04, - others_write = 02, - others_exec = 01, - others_all = 07, - - all = 0777, - set_uid = 04000, - set_gid = 02000, - sticky_bit = 01000, - - mask = 07777, - unknown = 0xffff -}; - -// [fs.enum.perm.opts] -enum class perm_options : uint16_t { - replace = 3, - add = 1, - remove = 2, - nofollow = 4, -}; - -// [fs.enum.copy.opts] -enum class copy_options : uint16_t { - none = 0, - - skip_existing = 1, - overwrite_existing = 2, - update_existing = 4, - - recursive = 8, - - copy_symlinks = 0x10, - skip_symlinks = 0x20, - - directories_only = 0x40, - create_symlinks = 0x80, -#ifndef GHC_OS_WEB - create_hard_links = 0x100 -#endif -}; - -// [fs.enum.dir.opts] -enum class directory_options : uint16_t { - none = 0, - follow_directory_symlink = 1, - skip_permission_denied = 2, -}; - -// [fs.class.file_status] class file_status -class GHC_FS_API_CLASS file_status -{ -public: - // [fs.file_status.cons] constructors and destructor - file_status() noexcept; - explicit file_status(file_type ft, perms prms = perms::unknown) noexcept; - file_status(const file_status&) noexcept; - file_status(file_status&&) noexcept; - ~file_status(); - // assignments: - file_status& operator=(const file_status&) noexcept; - file_status& operator=(file_status&&) noexcept; - // [fs.file_status.mods] modifiers - void type(file_type ft) noexcept; - void permissions(perms prms) noexcept; - // [fs.file_status.obs] observers - file_type type() const noexcept; - perms permissions() const noexcept; - friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); } -private: - file_type _type; - perms _perms; -}; - -using file_time_type = std::chrono::time_point; - -// [fs.class.directory_entry] Class directory_entry -class GHC_FS_API_CLASS directory_entry -{ -public: - // [fs.dir.entry.cons] constructors and destructor - directory_entry() noexcept = default; - directory_entry(const directory_entry&) = default; - directory_entry(directory_entry&&) noexcept = default; -#ifdef GHC_WITH_EXCEPTIONS - explicit directory_entry(const path& p); -#endif - directory_entry(const path& p, std::error_code& ec); - ~directory_entry(); - - // assignments: - directory_entry& operator=(const directory_entry&) = default; - directory_entry& operator=(directory_entry&&) noexcept = default; - - // [fs.dir.entry.mods] modifiers -#ifdef GHC_WITH_EXCEPTIONS - void assign(const path& p); - void replace_filename(const path& p); - void refresh(); -#endif - void assign(const path& p, std::error_code& ec); - void replace_filename(const path& p, std::error_code& ec); - void refresh(std::error_code& ec) noexcept; - - // [fs.dir.entry.obs] observers - const filesystem::path& path() const noexcept; - operator const filesystem::path&() const noexcept; -#ifdef GHC_WITH_EXCEPTIONS - bool exists() const; - bool is_block_file() const; - bool is_character_file() const; - bool is_directory() const; - bool is_fifo() const; - bool is_other() const; - bool is_regular_file() const; - bool is_socket() const; - bool is_symlink() const; - uintmax_t file_size() const; - file_time_type last_write_time() const; - file_status status() const; - file_status symlink_status() const; -#endif - bool exists(std::error_code& ec) const noexcept; - bool is_block_file(std::error_code& ec) const noexcept; - bool is_character_file(std::error_code& ec) const noexcept; - bool is_directory(std::error_code& ec) const noexcept; - bool is_fifo(std::error_code& ec) const noexcept; - bool is_other(std::error_code& ec) const noexcept; - bool is_regular_file(std::error_code& ec) const noexcept; - bool is_socket(std::error_code& ec) const noexcept; - bool is_symlink(std::error_code& ec) const noexcept; - uintmax_t file_size(std::error_code& ec) const noexcept; - file_time_type last_write_time(std::error_code& ec) const noexcept; - file_status status(std::error_code& ec) const noexcept; - file_status symlink_status(std::error_code& ec) const noexcept; - -#ifndef GHC_OS_WEB -#ifdef GHC_WITH_EXCEPTIONS - uintmax_t hard_link_count() const; -#endif - uintmax_t hard_link_count(std::error_code& ec) const noexcept; -#endif - -#ifdef GHC_HAS_THREEWAY_COMP - std::strong_ordering operator<=>(const directory_entry& rhs) const noexcept; -#endif - bool operator<(const directory_entry& rhs) const noexcept; - bool operator==(const directory_entry& rhs) const noexcept; - bool operator!=(const directory_entry& rhs) const noexcept; - bool operator<=(const directory_entry& rhs) const noexcept; - bool operator>(const directory_entry& rhs) const noexcept; - bool operator>=(const directory_entry& rhs) const noexcept; - -private: - friend class directory_iterator; -#ifdef GHC_WITH_EXCEPTIONS - file_type status_file_type() const; -#endif - file_type status_file_type(std::error_code& ec) const noexcept; - filesystem::path _path; - file_status _status; - file_status _symlink_status; - uintmax_t _file_size = static_cast(-1); -#ifndef GHC_OS_WINDOWS - uintmax_t _hard_link_count = static_cast(-1); -#endif - time_t _last_write_time = 0; -}; - -// [fs.class.directory.iterator] Class directory_iterator -class GHC_FS_API_CLASS directory_iterator -{ -public: - class GHC_FS_API_CLASS proxy - { - public: - const directory_entry& operator*() const& noexcept { return _dir_entry; } - directory_entry operator*() && noexcept { return std::move(_dir_entry); } - - private: - explicit proxy(const directory_entry& dir_entry) - : _dir_entry(dir_entry) - { - } - friend class directory_iterator; - friend class recursive_directory_iterator; - directory_entry _dir_entry; - }; - using iterator_category = std::input_iterator_tag; - using value_type = directory_entry; - using difference_type = std::ptrdiff_t; - using pointer = const directory_entry*; - using reference = const directory_entry&; - - // [fs.dir.itr.members] member functions - directory_iterator() noexcept; -#ifdef GHC_WITH_EXCEPTIONS - explicit directory_iterator(const path& p); - directory_iterator(const path& p, directory_options options); -#endif - directory_iterator(const path& p, std::error_code& ec) noexcept; - directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; - directory_iterator(const directory_iterator& rhs); - directory_iterator(directory_iterator&& rhs) noexcept; - ~directory_iterator(); - directory_iterator& operator=(const directory_iterator& rhs); - directory_iterator& operator=(directory_iterator&& rhs) noexcept; - const directory_entry& operator*() const; - const directory_entry* operator->() const; -#ifdef GHC_WITH_EXCEPTIONS - directory_iterator& operator++(); -#endif - directory_iterator& increment(std::error_code& ec) noexcept; - - // other members as required by [input.iterators] -#ifdef GHC_WITH_EXCEPTIONS - proxy operator++(int) - { - proxy p{**this}; - ++*this; - return p; - } -#endif - bool operator==(const directory_iterator& rhs) const; - bool operator!=(const directory_iterator& rhs) const; - -private: - friend class recursive_directory_iterator; - class impl; - std::shared_ptr _impl; -}; - -// [fs.dir.itr.nonmembers] directory_iterator non-member functions -GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept; -GHC_FS_API directory_iterator end(const directory_iterator&) noexcept; - -// [fs.class.re.dir.itr] class recursive_directory_iterator -class GHC_FS_API_CLASS recursive_directory_iterator -{ -public: - using iterator_category = std::input_iterator_tag; - using value_type = directory_entry; - using difference_type = std::ptrdiff_t; - using pointer = const directory_entry*; - using reference = const directory_entry&; - - // [fs.rec.dir.itr.members] constructors and destructor - recursive_directory_iterator() noexcept; -#ifdef GHC_WITH_EXCEPTIONS - explicit recursive_directory_iterator(const path& p); - recursive_directory_iterator(const path& p, directory_options options); -#endif - recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; - recursive_directory_iterator(const path& p, std::error_code& ec) noexcept; - recursive_directory_iterator(const recursive_directory_iterator& rhs); - recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept; - ~recursive_directory_iterator(); - - // [fs.rec.dir.itr.members] observers - directory_options options() const; - int depth() const; - bool recursion_pending() const; - - const directory_entry& operator*() const; - const directory_entry* operator->() const; - - // [fs.rec.dir.itr.members] modifiers recursive_directory_iterator& - recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs); - recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept; -#ifdef GHC_WITH_EXCEPTIONS - recursive_directory_iterator& operator++(); -#endif - recursive_directory_iterator& increment(std::error_code& ec) noexcept; - -#ifdef GHC_WITH_EXCEPTIONS - void pop(); -#endif - void pop(std::error_code& ec); - void disable_recursion_pending(); - - // other members as required by [input.iterators] -#ifdef GHC_WITH_EXCEPTIONS - directory_iterator::proxy operator++(int) - { - directory_iterator::proxy proxy{**this}; - ++*this; - return proxy; - } -#endif - bool operator==(const recursive_directory_iterator& rhs) const; - bool operator!=(const recursive_directory_iterator& rhs) const; - -private: - struct recursive_directory_iterator_impl - { - directory_options _options; - bool _recursion_pending; - std::stack _dir_iter_stack; - recursive_directory_iterator_impl(directory_options options, bool recursion_pending) - : _options(options) - , _recursion_pending(recursion_pending) - { - } - }; - std::shared_ptr _impl; -}; - -// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions -GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; -GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; - -// [fs.op.funcs] filesystem operations -#ifdef GHC_WITH_EXCEPTIONS -GHC_FS_API path absolute(const path& p); -GHC_FS_API path canonical(const path& p); -GHC_FS_API void copy(const path& from, const path& to); -GHC_FS_API void copy(const path& from, const path& to, copy_options options); -GHC_FS_API bool copy_file(const path& from, const path& to); -GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option); -GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink); -GHC_FS_API bool create_directories(const path& p); -GHC_FS_API bool create_directory(const path& p); -GHC_FS_API bool create_directory(const path& p, const path& attributes); -GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink); -GHC_FS_API void create_symlink(const path& to, const path& new_symlink); -GHC_FS_API path current_path(); -GHC_FS_API void current_path(const path& p); -GHC_FS_API bool exists(const path& p); -GHC_FS_API bool equivalent(const path& p1, const path& p2); -GHC_FS_API uintmax_t file_size(const path& p); -GHC_FS_API bool is_block_file(const path& p); -GHC_FS_API bool is_character_file(const path& p); -GHC_FS_API bool is_directory(const path& p); -GHC_FS_API bool is_empty(const path& p); -GHC_FS_API bool is_fifo(const path& p); -GHC_FS_API bool is_other(const path& p); -GHC_FS_API bool is_regular_file(const path& p); -GHC_FS_API bool is_socket(const path& p); -GHC_FS_API bool is_symlink(const path& p); -GHC_FS_API file_time_type last_write_time(const path& p); -GHC_FS_API void last_write_time(const path& p, file_time_type new_time); -GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace); -GHC_FS_API path proximate(const path& p, const path& base = current_path()); -GHC_FS_API path read_symlink(const path& p); -GHC_FS_API path relative(const path& p, const path& base = current_path()); -GHC_FS_API bool remove(const path& p); -GHC_FS_API uintmax_t remove_all(const path& p); -GHC_FS_API void rename(const path& from, const path& to); -GHC_FS_API void resize_file(const path& p, uintmax_t size); -GHC_FS_API space_info space(const path& p); -GHC_FS_API file_status status(const path& p); -GHC_FS_API file_status symlink_status(const path& p); -GHC_FS_API path temp_directory_path(); -GHC_FS_API path weakly_canonical(const path& p); -#endif -GHC_FS_API path absolute(const path& p, std::error_code& ec); -GHC_FS_API path canonical(const path& p, std::error_code& ec); -GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept; -GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept; -GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept; -GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept; -GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept; -GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept; -GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; -GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; -GHC_FS_API path current_path(std::error_code& ec); -GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool exists(file_status s) noexcept; -GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept; -GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_block_file(file_status s) noexcept; -GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_character_file(file_status s) noexcept; -GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_directory(file_status s) noexcept; -GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_fifo(file_status s) noexcept; -GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_other(file_status s) noexcept; -GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_regular_file(file_status s) noexcept; -GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_socket(file_status s) noexcept; -GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_symlink(file_status s) noexcept; -GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept; -GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept; -GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept; -GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept; -GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept; -GHC_FS_API path proximate(const path& p, std::error_code& ec); -GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec); -GHC_FS_API path read_symlink(const path& p, std::error_code& ec); -GHC_FS_API path relative(const path& p, std::error_code& ec); -GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec); -GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept; -GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept; -GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept; -GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept; -GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept; -GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool status_known(file_status s) noexcept; -GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept; -GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept; -GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept; - -#ifndef GHC_OS_WEB -#ifdef GHC_WITH_EXCEPTIONS -GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link); -GHC_FS_API uintmax_t hard_link_count(const path& p); -#endif -GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept; -GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; -#endif - -// Non-C++17 add-on std::fstream wrappers with path -template > -class basic_filebuf : public std::basic_filebuf -{ -public: - basic_filebuf() {} - ~basic_filebuf() override {} - basic_filebuf(const basic_filebuf&) = delete; - const basic_filebuf& operator=(const basic_filebuf&) = delete; - basic_filebuf* open(const path& p, std::ios_base::openmode mode) - { -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) - return std::basic_filebuf::open(p.wstring().c_str(), mode) ? this : 0; -#else - return std::basic_filebuf::open(p.string().c_str(), mode) ? this : 0; -#endif - } -}; - -template > -class basic_ifstream : public std::basic_ifstream -{ -public: - basic_ifstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) - explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) - : std::basic_ifstream(p.wstring().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.wstring().c_str(), mode); } -#else - explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) - : std::basic_ifstream(p.string().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.string().c_str(), mode); } -#endif - basic_ifstream(const basic_ifstream&) = delete; - const basic_ifstream& operator=(const basic_ifstream&) = delete; - ~basic_ifstream() override {} -}; - -template > -class basic_ofstream : public std::basic_ofstream -{ -public: - basic_ofstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) - explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) - : std::basic_ofstream(p.wstring().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.wstring().c_str(), mode); } -#else - explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) - : std::basic_ofstream(p.string().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.string().c_str(), mode); } -#endif - basic_ofstream(const basic_ofstream&) = delete; - const basic_ofstream& operator=(const basic_ofstream&) = delete; - ~basic_ofstream() override {} -}; - -template > -class basic_fstream : public std::basic_fstream -{ -public: - basic_fstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) - explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : std::basic_fstream(p.wstring().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.wstring().c_str(), mode); } -#else - explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : std::basic_fstream(p.string().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.string().c_str(), mode); } -#endif - basic_fstream(const basic_fstream&) = delete; - const basic_fstream& operator=(const basic_fstream&) = delete; - ~basic_fstream() override {} -}; - -typedef basic_filebuf filebuf; -typedef basic_filebuf wfilebuf; -typedef basic_ifstream ifstream; -typedef basic_ifstream wifstream; -typedef basic_ofstream ofstream; -typedef basic_ofstream wofstream; -typedef basic_fstream fstream; -typedef basic_fstream wfstream; - -class GHC_FS_API_CLASS u8arguments -{ -public: - u8arguments(int& argc, char**& argv); - ~u8arguments() - { - _refargc = _argc; - _refargv = _argv; - } - - bool valid() const { return _isvalid; } - -private: - int _argc; - char** _argv; - int& _refargc; - char**& _refargv; - bool _isvalid; -#ifdef GHC_OS_WINDOWS - std::vector _args; - std::vector _argp; -#endif -}; - -//------------------------------------------------------------------------------------------------- -// Implementation -//------------------------------------------------------------------------------------------------- - -namespace detail { -enum utf8_states_t { S_STRT = 0, S_RJCT = 8 }; -GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode); -GHC_FS_API bool is_surrogate(uint32_t c); -GHC_FS_API bool is_high_surrogate(uint32_t c); -GHC_FS_API bool is_low_surrogate(uint32_t c); -GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint); -enum class portable_error { - none = 0, - exists, - not_found, - not_supported, - not_implemented, - invalid_argument, - is_a_directory, -}; -GHC_FS_API std::error_code make_error_code(portable_error err); -#ifdef GHC_OS_WINDOWS -GHC_FS_API std::error_code make_system_error(uint32_t err = 0); -#else -GHC_FS_API std::error_code make_system_error(int err = 0); -#endif -} // namespace detail - -namespace detail { - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE std::error_code make_error_code(portable_error err) -{ -#ifdef GHC_OS_WINDOWS - switch (err) { - case portable_error::none: - return std::error_code(); - case portable_error::exists: - return std::error_code(ERROR_ALREADY_EXISTS, std::system_category()); - case portable_error::not_found: - return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category()); - case portable_error::not_supported: - return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); - case portable_error::not_implemented: - 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: -#ifdef ERROR_DIRECTORY_NOT_SUPPORTED - return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); -#else - return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); -#endif - } -#else - switch (err) { - case portable_error::none: - return std::error_code(); - case portable_error::exists: - return std::error_code(EEXIST, std::system_category()); - case portable_error::not_found: - return std::error_code(ENOENT, std::system_category()); - case portable_error::not_supported: - return std::error_code(ENOTSUP, std::system_category()); - case portable_error::not_implemented: - 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(); -} - -#ifdef GHC_OS_WINDOWS -GHC_INLINE std::error_code make_system_error(uint32_t err) -{ - return std::error_code(err ? static_cast(err) : static_cast(::GetLastError()), std::system_category()); -} -#else -GHC_INLINE std::error_code make_system_error(int err) -{ - return std::error_code(err ? err : errno, std::system_category()); -} -#endif - -#endif // GHC_EXPAND_IMPL - -template -using EnableBitmask = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, Enum>::type; -} // namespace detail - -template -constexpr detail::EnableBitmask operator&(Enum X, Enum Y) -{ - using underlying = typename std::underlying_type::type; - return static_cast(static_cast(X) & static_cast(Y)); -} - -template -constexpr detail::EnableBitmask operator|(Enum X, Enum Y) -{ - using underlying = typename std::underlying_type::type; - return static_cast(static_cast(X) | static_cast(Y)); -} - -template -constexpr detail::EnableBitmask operator^(Enum X, Enum Y) -{ - using underlying = typename std::underlying_type::type; - return static_cast(static_cast(X) ^ static_cast(Y)); -} - -template -constexpr detail::EnableBitmask operator~(Enum X) -{ - using underlying = typename std::underlying_type::type; - return static_cast(~static_cast(X)); -} - -template -detail::EnableBitmask& operator&=(Enum& X, Enum Y) -{ - X = X & Y; - return X; -} - -template -detail::EnableBitmask& operator|=(Enum& X, Enum Y) -{ - X = X | Y; - return X; -} - -template -detail::EnableBitmask& operator^=(Enum& X, Enum Y) -{ - X = X ^ Y; - return X; -} - -#ifdef GHC_EXPAND_IMPL - -namespace detail { - -GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi) -{ - return (static_cast(c - lo) < (hi - lo + 1)); -} - -GHC_INLINE bool is_surrogate(uint32_t c) -{ - return in_range(c, 0xd800, 0xdfff); -} - -GHC_INLINE bool is_high_surrogate(uint32_t c) -{ - return (c & 0xfffffc00) == 0xd800; -} - -GHC_INLINE bool is_low_surrogate(uint32_t c) -{ - return (c & 0xfffffc00) == 0xdc00; -} - -GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode) -{ - if (unicode <= 0x7f) { - str.push_back(static_cast(unicode)); - } - else if (unicode >= 0x80 && unicode <= 0x7ff) { - str.push_back(static_cast((unicode >> 6) + 192)); - str.push_back(static_cast((unicode & 0x3f) + 128)); - } - else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) { - str.push_back(static_cast((unicode >> 12) + 224)); - str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); - str.push_back(static_cast((unicode & 0x3f) + 128)); - } - else if (unicode >= 0x10000 && unicode <= 0x10ffff) { - str.push_back(static_cast((unicode >> 18) + 240)); - str.push_back(static_cast(((unicode & 0x3ffff) >> 12) + 128)); - str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); - str.push_back(static_cast((unicode & 0x3f) + 128)); - } - else { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal code point for unicode character.", str, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - appendUTF8(str, 0xfffd); -#endif - } -} - -// Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/) -// and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding; -// Generating debugging and shrinking my own DFA from scratch was a day of fun! -GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint) -{ - static const uint32_t utf8_state_info[] = { - // encoded states - 0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u, - 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u, 0u, 0u, - }; - uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf; - codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment); - return state == S_RJCT ? static_cast(S_RJCT) : static_cast((utf8_state_info[category + 16] >> (state << 2)) & 0xf); -} - -GHC_INLINE bool validUtf8(const std::string& utf8String) -{ - std::string::const_iterator iter = utf8String.begin(); - unsigned utf8_state = S_STRT; - std::uint32_t codepoint = 0; - while (iter < utf8String.end()) { - if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_RJCT) { - return false; - } - } - if (utf8_state) { - return false; - } - return true; -} - -} // namespace detail - -#endif - -namespace detail { - -template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 1)>::type* = nullptr> -inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - return StringType(utf8String.begin(), utf8String.end(), alloc); -} - -template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 2)>::type* = nullptr> -inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - StringType result(alloc); - result.reserve(utf8String.length()); - auto iter = utf8String.cbegin(); - unsigned utf8_state = S_STRT; - std::uint32_t codepoint = 0; - while (iter < utf8String.cend()) { - if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { - if (codepoint <= 0xffff) { - result += static_cast(codepoint); - } - else { - codepoint -= 0x10000; - result += static_cast((codepoint >> 10) + 0xd800); - result += static_cast((codepoint & 0x3ff) + 0xdc00); - } - codepoint = 0; - } - else if (utf8_state == S_RJCT) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); - utf8_state = S_STRT; - codepoint = 0; -#endif - } - } - if (utf8_state) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); -#endif - } - return result; -} - -template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 4)>::type* = nullptr> -inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - StringType result(alloc); - result.reserve(utf8String.length()); - auto iter = utf8String.cbegin(); - unsigned utf8_state = S_STRT; - std::uint32_t codepoint = 0; - while (iter < utf8String.cend()) { - if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { - result += static_cast(codepoint); - codepoint = 0; - } - else if (utf8_state == S_RJCT) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); - utf8_state = S_STRT; - codepoint = 0; -#endif - } - } - if (utf8_state) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); -#endif - } - return result; -} - -template -inline StringType fromUtf8(const charT (&utf8String)[N]) -{ -#ifdef GHC_WITH_STRING_VIEW - return fromUtf8(basic_string_view(utf8String, N - 1)); -#else - return fromUtf8(std::basic_string(utf8String, N - 1)); -#endif -} - -template ::value && (sizeof(typename strT::value_type) == 1), int>::type size = 1> -inline std::string toUtf8(const strT& unicodeString) -{ - return std::string(unicodeString.begin(), unicodeString.end()); -} - -template ::value && (sizeof(typename strT::value_type) == 2), int>::type size = 2> -inline std::string toUtf8(const strT& unicodeString) -{ - std::string result; - for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) { - char32_t c = *iter; - if (is_surrogate(c)) { - ++iter; - if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) { - appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00); - } - else { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - appendUTF8(result, 0xfffd); - if (iter == unicodeString.end()) { - break; - } -#endif - } - } - else { - appendUTF8(result, c); - } - } - return result; -} - -template ::value && (sizeof(typename strT::value_type) == 4), int>::type size = 4> -inline std::string toUtf8(const strT& unicodeString) -{ - std::string result; - for (auto c : unicodeString) { - appendUTF8(result, static_cast(c)); - } - return result; -} - -template -inline std::string toUtf8(const charT* unicodeString) -{ -#ifdef GHC_WITH_STRING_VIEW - return toUtf8(basic_string_view>(unicodeString)); -#else - return toUtf8(std::basic_string>(unicodeString)); -#endif -} - -#ifdef GHC_USE_WCHAR_T -template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 1), bool>::type = false> -inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - auto temp = toUtf8(wString); - return StringType(temp.begin(), temp.end(), alloc); -} - -template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 2), bool>::type = false> -inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - return StringType(wString.begin(), wString.end(), alloc); -} - -template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 4), bool>::type = false> -inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - auto temp = toUtf8(wString); - return fromUtf8(temp, alloc); -} - -template ::value && (sizeof(typename strT::value_type) == 1), bool>::type = false> -inline std::wstring toWChar(const strT& unicodeString) -{ - return fromUtf8(unicodeString); -} - -template ::value && (sizeof(typename strT::value_type) == 2), bool>::type = false> -inline std::wstring toWChar(const strT& unicodeString) -{ - return std::wstring(unicodeString.begin(), unicodeString.end()); -} - -template ::value && (sizeof(typename strT::value_type) == 4), bool>::type = false> -inline std::wstring toWChar(const strT& unicodeString) -{ - auto temp = toUtf8(unicodeString); - return fromUtf8(temp); -} - -template -inline std::wstring toWChar(const charT* unicodeString) -{ -#ifdef GHC_WITH_STRING_VIEW - return toWChar(basic_string_view>(unicodeString)); -#else - return toWChar(std::basic_string>(unicodeString)); -#endif -} -#endif // GHC_USE_WCHAR_T - -} // namespace detail - -#ifdef GHC_EXPAND_IMPL - -namespace detail { - -template ::value, bool>::type = true> -GHC_INLINE bool startsWith(const strT& what, const strT& with) -{ - return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin()); -} - -template ::value, bool>::type = true> -GHC_INLINE bool endsWith(const strT& what, const strT& with) -{ - return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with) == 0; -} - -} // namespace detail - -GHC_INLINE void path::check_long_path() -{ -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) { - postprocess_path_with_format(native_format); - } -#endif -} - -GHC_INLINE void path::postprocess_path_with_format(path::format fmt) -{ -#ifdef GHC_RAISE_UNICODE_ERRORS - if (!detail::validUtf8(_path)) { - path t; - t._path = _path; - throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence)); - } -#endif - switch (fmt) { -#ifdef GHC_OS_WINDOWS - case path::native_format: - case path::auto_format: - case path::generic_format: - for (auto& c : _path) { - if (c == generic_separator) { - c = preferred_separator; - } - } -#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH - if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) { - _path = GHC_PLATFORM_LITERAL("\\\\?\\") + _path; - } -#endif - handle_prefixes(); - break; -#else - case path::auto_format: - case path::native_format: - case path::generic_format: - // nothing to do - break; -#endif - } - if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator) { - impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast(_prefixLength) + 2, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; }); - _path.erase(new_end, _path.end()); - } - else { - impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast(_prefixLength), _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; }); - _path.erase(new_end, _path.end()); - } -} - -#endif // GHC_EXPAND_IMPL - -template -inline path::path(const Source& source, format fmt) -#ifdef GHC_USE_WCHAR_T - : _path(detail::toWChar(source)) -#else - : _path(detail::toUtf8(source)) -#endif -{ - postprocess_path_with_format(fmt); -} - -template -inline path u8path(const Source& source) -{ - return path(source); -} -template -inline path u8path(InputIterator first, InputIterator last) -{ - return path(first, last); -} - -template -inline path::path(InputIterator first, InputIterator last, format fmt) - : path(std::basic_string::value_type>(first, last), fmt) -{ - // delegated -} - -#ifdef GHC_EXPAND_IMPL - -namespace detail { - -GHC_INLINE bool equals_simple_insensitive(const path::value_type* str1, const path::value_type* str2) -{ -#ifdef GHC_OS_WINDOWS -#ifdef __GNUC__ - while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) { - if (*str1++ == 0) - return true; - } - return false; -#else // __GNUC__ -#ifdef GHC_USE_WCHAR_T - return 0 == ::_wcsicmp(str1, str2); -#else // GHC_USE_WCHAR_T - return 0 == ::_stricmp(str1, str2); -#endif // GHC_USE_WCHAR_T -#endif // __GNUC__ -#else // GHC_OS_WINDOWS - return 0 == ::strcasecmp(str1, str2); -#endif // GHC_OS_WINDOWS -} - -GHC_INLINE int compare_simple_insensitive(const path::value_type* str1, size_t len1, const path::value_type* str2, size_t len2) -{ - while (len1 > 0 && len2 > 0 && ::tolower(static_cast(*str1)) == ::tolower(static_cast(*str2))) { - --len1; - --len2; - ++str1; - ++str2; - } - if (len1 && len2) { - return *str1 < *str2 ? -1 : 1; - } - if (len1 == 0 && len2 == 0) { - return 0; - } - return len1 == 0 ? -1 : 1; -} - -GHC_INLINE const char* strerror_adapter(char* gnu, char*) -{ - return gnu; -} - -GHC_INLINE const char* strerror_adapter(int posix, char* buffer) -{ - if (posix) { - return "Error in strerror_r!"; - } - return buffer; -} - -template -GHC_INLINE std::string systemErrorText(ErrorNumber code = 0) -{ -#if defined(GHC_OS_WINDOWS) - LPVOID msgBuf; - DWORD dw = code ? static_cast(code) : ::GetLastError(); - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL); - std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf)); - LocalFree(msgBuf); - return msg; -#else - char buffer[512]; - return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer); -#endif -} - -#ifdef GHC_OS_WINDOWS -using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD); -using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); - -GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec) -{ - std::error_code tec; - auto fs = status(target_name, tec); - if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) { - ec = detail::make_error_code(detail::portable_error::not_supported); - return; - } -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - static CreateSymbolicLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic pop -#endif - if (api_call) { - if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) { - auto result = ::GetLastError(); - if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 3 : 2) != 0) { - return; - } - ec = detail::make_system_error(result); - } - } - else { - ec = detail::make_system_error(ERROR_NOT_SUPPORTED); - } -} - -GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) -{ -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - static CreateHardLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic pop -#endif - if (api_call) { - if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) { - ec = detail::make_system_error(); - } - } - else { - ec = detail::make_system_error(ERROR_NOT_SUPPORTED); - } -} - -GHC_INLINE path getFullPathName(const wchar_t* p, std::error_code& ec) -{ - ULONG size = ::GetFullPathNameW(p, 0, 0, 0); - if (size) { - std::vector buf(size, 0); - ULONG s2 = GetFullPathNameW(p, size, buf.data(), nullptr); - if (s2 && s2 < size) { - return path(std::wstring(buf.data(), s2)); - } - } - ec = detail::make_system_error(); - return path(); -} - -#else -GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec) -{ - if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) { - ec = detail::make_system_error(); - } -} - -#ifndef GHC_OS_WEB -GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) -{ - if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) { - ec = detail::make_system_error(); - } -} -#endif -#endif - -template -GHC_INLINE file_status file_status_from_st_mode(T mode) -{ -#ifdef GHC_OS_WINDOWS - file_type ft = file_type::unknown; - if ((mode & _S_IFDIR) == _S_IFDIR) { - ft = file_type::directory; - } - else if ((mode & _S_IFREG) == _S_IFREG) { - ft = file_type::regular; - } - else if ((mode & _S_IFCHR) == _S_IFCHR) { - ft = file_type::character; - } - perms prms = static_cast(mode & 0xfff); - return file_status(ft, prms); -#else - file_type ft = file_type::unknown; - if (S_ISDIR(mode)) { - ft = file_type::directory; - } - else if (S_ISREG(mode)) { - ft = file_type::regular; - } - else if (S_ISCHR(mode)) { - ft = file_type::character; - } - else if (S_ISBLK(mode)) { - ft = file_type::block; - } - else if (S_ISFIFO(mode)) { - ft = file_type::fifo; - } - else if (S_ISLNK(mode)) { - ft = file_type::symlink; - } - else if (S_ISSOCK(mode)) { - ft = file_type::socket; - } - perms prms = static_cast(mode & 0xfff); - return file_status(ft, prms); -#endif -} - -#ifdef GHC_OS_WINDOWS -#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE -typedef struct _REPARSE_DATA_BUFFER -{ - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union - { - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct - { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - } DUMMYUNIONNAME; -} REPARSE_DATA_BUFFER; -#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) -#endif -#endif - -GHC_INLINE std::shared_ptr getReparseData(const path& p, std::error_code& ec) -{ - std::shared_ptr file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - if (file.get() == INVALID_HANDLE_VALUE) { - ec = detail::make_system_error(); - return nullptr; - } - - std::shared_ptr reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free); - ULONG bufferUsed; - if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { - return reparseData; - } - else { - ec = detail::make_system_error(); - } - return nullptr; -} -#endif - -GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) -{ -#ifdef GHC_OS_WINDOWS - path result; - auto reparseData = detail::getReparseData(p, ec); - if (!ec) { - if (reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag)) { - switch (reparseData->ReparseTag) { - case IO_REPARSE_TAG_SYMLINK: { - auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR)); - auto substituteName = - std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); - if (detail::endsWith(substituteName, printName) && detail::startsWith(substituteName, std::wstring(L"\\??\\"))) { - result = printName; - } - else { - result = substituteName; - } - if (reparseData->SymbolicLinkReparseBuffer.Flags & 0x1 /*SYMLINK_FLAG_RELATIVE*/) { - result = p.parent_path() / result; - } - break; - } - case IO_REPARSE_TAG_MOUNT_POINT: - result = detail::getFullPathName(GHC_NATIVEWP(p), ec); - //result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); - break; - default: - break; - } - } - } - return result; -#else - size_t bufferSize = 256; - while (true) { - std::vector buffer(bufferSize, static_cast(0)); - auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size()); - if (rc < 0) { - ec = detail::make_system_error(); - return path(); - } - else if (rc < static_cast(bufferSize)) { - return path(std::string(buffer.data(), static_cast(rc))); - } - bufferSize *= 2; - } - return path(); -#endif -} - -#ifdef GHC_OS_WINDOWS -GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft) -{ - ULARGE_INTEGER ull; - ull.LowPart = ft.dwLowDateTime; - ull.HighPart = ft.dwHighDateTime; - return static_cast(ull.QuadPart / 10000000ULL - 11644473600ULL); -} - -GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) -{ - LONGLONG ll; - ll = Int32x32To64(t, 10000000) + 116444736000000000; - ft.dwLowDateTime = static_cast(ll); - ft.dwHighDateTime = static_cast(ll >> 32); -} - -template -GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info) -{ - return static_cast(-1); -} - -template <> -GHC_INLINE uintmax_t hard_links_from_INFO(const BY_HANDLE_FILE_INFORMATION* info) -{ - return info->nNumberOfLinks; -} - -template -GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*) -{ - return 0; -} - -template <> -GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info) -{ - return info->dwReserved0; -} - -template -GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr) -{ - file_type ft = file_type::unknown; - if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) { - if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) { - ft = file_type::symlink; - } - } - else { - if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - auto reparseData = detail::getReparseData(p, ec); - if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { - ft = file_type::symlink; - } - } - } - if (ft == file_type::unknown) { - if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - ft = file_type::directory; - } - else { - ft = file_type::regular; - } - } - perms prms = perms::owner_read | perms::group_read | perms::others_read; - if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { - prms = prms | perms::owner_write | perms::group_write | perms::others_write; - } - if (has_executable_extension(p)) { - prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec; - } - if (sz) { - *sz = static_cast(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow; - } - if (lwt) { - *lwt = detail::timeFromFILETIME(info->ftLastWriteTime); - } - return file_status(ft, prms); -} - -#endif - -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 || ec.value() == ERROR_INVALID_NAME; -#else - return ec.value() == ENOENT || ec.value() == ENOTDIR; -#endif -} - -GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept -{ -#ifdef GHC_OS_WINDOWS - file_status fs; - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { - ec = detail::make_system_error(); - } - else { - ec.clear(); - fs = detail::status_from_INFO(p, &attr, ec, sz, lwt); - if (nhl) { - *nhl = 0; - } - } - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found); - } - return ec ? file_status(file_type::none) : fs; -#else - (void)sz; - (void)nhl; - (void)lwt; - struct ::stat fs; - auto result = ::lstat(p.c_str(), &fs); - if (result == 0) { - ec.clear(); - file_status f_s = detail::file_status_from_st_mode(fs.st_mode); - return f_s; - } - ec = detail::make_system_error(); - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found, perms::unknown); - } - return file_status(file_type::none); -#endif -} - -GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (recurse_count > 16) { - ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/); - return file_status(file_type::unknown); - } - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!::GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { - ec = detail::make_system_error(); - } - else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - auto reparseData = detail::getReparseData(p, ec); - if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { - path target = resolveSymlink(p, ec); - file_status result; - if (!ec && !target.empty()) { - if (sls) { - *sls = status_from_INFO(p, &attr, ec); - } - return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); - } - return file_status(file_type::unknown); - } - } - if (ec) { - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found); - } - return file_status(file_type::none); - } - if (nhl) { - *nhl = 0; - } - return detail::status_from_INFO(p, &attr, ec, sz, lwt); -#else - (void)recurse_count; - struct ::stat st; - auto result = ::lstat(p.c_str(), &st); - if (result == 0) { - ec.clear(); - file_status fs = detail::file_status_from_st_mode(st.st_mode); - if (sls) { - *sls = fs; - } - if (fs.type() == file_type::symlink) { - result = ::stat(p.c_str(), &st); - if (result == 0) { - fs = detail::file_status_from_st_mode(st.st_mode); - } - else { - ec = detail::make_system_error(); - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found, perms::unknown); - } - return file_status(file_type::none); - } - } - if (sz) { - *sz = static_cast(st.st_size); - } - if (nhl) { - *nhl = st.st_nlink; - } - if (lwt) { - *lwt = st.st_mtime; - } - return fs; - } - else { - ec = detail::make_system_error(); - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found, perms::unknown); - } - return file_status(file_type::none); - } -#endif -} - -} // namespace detail - -GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv) - : _argc(argc) - , _argv(argv) - , _refargc(argc) - , _refargv(argv) - , _isvalid(false) -{ -#ifdef GHC_OS_WINDOWS - LPWSTR* p; - p = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - _args.reserve(static_cast(argc)); - _argp.reserve(static_cast(argc)); - for (size_t i = 0; i < static_cast(argc); ++i) { - _args.push_back(detail::toUtf8(std::wstring(p[i]))); - _argp.push_back((char*)_args[i].data()); - } - argv = _argp.data(); - ::LocalFree(p); - _isvalid = true; -#else - std::setlocale(LC_ALL, ""); -#if defined(__ANDROID__) && __ANDROID_API__ < 26 - _isvalid = true; -#else - if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) { - _isvalid = true; - } -#endif -#endif -} - -//----------------------------------------------------------------------------- -// [fs.path.construct] constructors and destructor - -GHC_INLINE path::path() noexcept {} - -GHC_INLINE path::path(const path& p) - : _path(p._path) -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - , _prefixLength(p._prefixLength) -#endif -{ -} - -GHC_INLINE path::path(path&& p) noexcept - : _path(std::move(p._path)) -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - , _prefixLength(p._prefixLength) -#endif -{ -} - -GHC_INLINE path::path(string_type&& source, format fmt) - : _path(std::move(source)) -{ - postprocess_path_with_format(fmt); -} - -#endif // GHC_EXPAND_IMPL - -#ifdef GHC_WITH_EXCEPTIONS -template -inline path::path(const Source& source, const std::locale& loc, format fmt) - : path(source, fmt) -{ - std::string locName = loc.name(); - if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { - throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); - } -} - -template -inline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt) - : path(std::basic_string::value_type>(first, last), fmt) -{ - std::string locName = loc.name(); - if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { - throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); - } -} -#endif - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE path::~path() {} - -//----------------------------------------------------------------------------- -// [fs.path.assign] assignments - -GHC_INLINE path& path::operator=(const path& p) -{ - _path = p._path; -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - _prefixLength = p._prefixLength; -#endif - return *this; -} - -GHC_INLINE path& path::operator=(path&& p) noexcept -{ - _path = std::move(p._path); -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - _prefixLength = p._prefixLength; -#endif - return *this; -} - -GHC_INLINE path& path::operator=(path::string_type&& source) -{ - return assign(source); -} - -GHC_INLINE path& path::assign(path::string_type&& source) -{ - _path = std::move(source); - postprocess_path_with_format(native_format); - return *this; -} - -#endif // GHC_EXPAND_IMPL - -template -inline path& path::operator=(const Source& source) -{ - return assign(source); -} - -template -inline path& path::assign(const Source& source) -{ -#ifdef GHC_USE_WCHAR_T - _path.assign(detail::toWChar(source)); -#else - _path.assign(detail::toUtf8(source)); -#endif - postprocess_path_with_format(native_format); - return *this; -} - -template <> -inline path& path::assign(const path& source) -{ - _path = source._path; -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - _prefixLength = source._prefixLength; -#endif - return *this; -} - -template -inline path& path::assign(InputIterator first, InputIterator last) -{ - _path.assign(first, last); - postprocess_path_with_format(native_format); - return *this; -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// [fs.path.append] appends - -GHC_INLINE path& path::operator/=(const path& p) -{ - if (p.empty()) { - // was: if ((!has_root_directory() && is_absolute()) || has_filename()) - if (!_path.empty() && _path[_path.length() - 1] != preferred_separator && _path[_path.length() - 1] != ':') { - _path += preferred_separator; - } - return *this; - } - if ((p.is_absolute() && (_path != root_name()._path || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) { - assign(p); - return *this; - } - if (p.has_root_directory()) { - assign(root_name()); - } - else if ((!has_root_directory() && is_absolute()) || has_filename()) { - _path += preferred_separator; - } - auto iter = p.begin(); - bool first = true; - if (p.has_root_name()) { - ++iter; - } - while (iter != p.end()) { - if (!first && !(!_path.empty() && _path[_path.length() - 1] == preferred_separator)) { - _path += preferred_separator; - } - first = false; - _path += (*iter++).native(); - } - check_long_path(); - return *this; -} - -GHC_INLINE void path::append_name(const value_type* name) -{ - if (_path.empty()) { - this->operator/=(path(name)); - } - else { - if (_path.back() != path::preferred_separator) { - _path.push_back(path::preferred_separator); - } - _path += name; - check_long_path(); - } -} - -#endif // GHC_EXPAND_IMPL - -template -inline path& path::operator/=(const Source& source) -{ - return append(source); -} - -template -inline path& path::append(const Source& source) -{ - return this->operator/=(path(source)); -} - -template <> -inline path& path::append(const path& p) -{ - return this->operator/=(p); -} - -template -inline path& path::append(InputIterator first, InputIterator last) -{ - std::basic_string::value_type> part(first, last); - return append(part); -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// [fs.path.concat] concatenation - -GHC_INLINE path& path::operator+=(const path& x) -{ - return concat(x._path); -} - -GHC_INLINE path& path::operator+=(const string_type& x) -{ - return concat(x); -} - -#ifdef GHC_WITH_STRING_VIEW -GHC_INLINE path& path::operator+=(basic_string_view x) -{ - return concat(x); -} -#endif - -GHC_INLINE path& path::operator+=(const value_type* x) -{ -#ifdef GHC_WITH_STRING_VIEW - basic_string_view part(x); -#else - string_type part(x); -#endif - return concat(part); -} - -GHC_INLINE path& path::operator+=(value_type x) -{ -#ifdef GHC_OS_WINDOWS - if (x == generic_separator) { - x = preferred_separator; - } -#endif - if (_path.empty() || _path.back() != preferred_separator) { - _path += x; - } - check_long_path(); - return *this; -} - -#endif // GHC_EXPAND_IMPL - -template -inline path::path_from_string& path::operator+=(const Source& x) -{ - return concat(x); -} - -template -inline path::path_type_EcharT& path::operator+=(EcharT x) -{ -#ifdef GHC_WITH_STRING_VIEW - basic_string_view part(&x, 1); -#else - std::basic_string part(1, x); -#endif - concat(part); - return *this; -} - -template -inline path& path::concat(const Source& x) -{ - path p(x); - _path += p._path; - postprocess_path_with_format(native_format); - return *this; -} -template -inline path& path::concat(InputIterator first, InputIterator last) -{ - _path.append(first, last); - postprocess_path_with_format(native_format); - return *this; -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// [fs.path.modifiers] modifiers -GHC_INLINE void path::clear() noexcept -{ - _path.clear(); -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - _prefixLength = 0; -#endif -} - -GHC_INLINE path& path::make_preferred() -{ - // as this filesystem implementation only uses generic_format - // internally, this must be a no-op - return *this; -} - -GHC_INLINE path& path::remove_filename() -{ - if (has_filename()) { - _path.erase(_path.size() - filename()._path.size()); - } - return *this; -} - -GHC_INLINE path& path::replace_filename(const path& replacement) -{ - remove_filename(); - return append(replacement); -} - -GHC_INLINE path& path::replace_extension(const path& replacement) -{ - if (has_extension()) { - _path.erase(_path.size() - extension()._path.size()); - } - if (!replacement.empty() && replacement._path[0] != '.') { - _path += '.'; - } - return concat(replacement); -} - -GHC_INLINE void path::swap(path& rhs) noexcept -{ - _path.swap(rhs._path); -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - std::swap(_prefixLength, rhs._prefixLength); -#endif -} - -//----------------------------------------------------------------------------- -// [fs.path.native.obs] native format observers -GHC_INLINE const path::string_type& path::native() const noexcept -{ - return _path; -} - -GHC_INLINE const path::value_type* path::c_str() const noexcept -{ - return native().c_str(); -} - -GHC_INLINE path::operator path::string_type() const -{ - return native(); -} - -#endif // GHC_EXPAND_IMPL - -template -inline std::basic_string path::string(const Allocator& a) const -{ -#ifdef GHC_USE_WCHAR_T - return detail::fromWChar>(_path, a); -#else - return detail::fromUtf8>(_path, a); -#endif -} - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE std::string path::string() const -{ -#ifdef GHC_USE_WCHAR_T - return detail::toUtf8(native()); -#else - return native(); -#endif -} - -GHC_INLINE std::wstring path::wstring() const -{ -#ifdef GHC_USE_WCHAR_T - return native(); -#else - return detail::fromUtf8(native()); -#endif -} - -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) -GHC_INLINE std::u8string path::u8string() const -{ -#ifdef GHC_USE_WCHAR_T - return std::u8string(reinterpret_cast(detail::toUtf8(native()).c_str())); -#else - return std::u8string(reinterpret_cast(c_str())); -#endif -} -#else -GHC_INLINE std::string path::u8string() const -{ -#ifdef GHC_USE_WCHAR_T - return detail::toUtf8(native()); -#else - return native(); -#endif -} -#endif - -GHC_INLINE std::u16string path::u16string() const -{ - // TODO: optimize - return detail::fromUtf8(string()); -} - -GHC_INLINE std::u32string path::u32string() const -{ - // TODO: optimize - return detail::fromUtf8(string()); -} - -#endif // GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// [fs.path.generic.obs] generic format observers -template -inline std::basic_string path::generic_string(const Allocator& a) const -{ -#ifdef GHC_OS_WINDOWS -#ifdef GHC_USE_WCHAR_T - auto result = detail::fromWChar, path::string_type>(_path, a); -#else - auto result = detail::fromUtf8>(_path, a); -#endif - for (auto& c : result) { - if (c == preferred_separator) { - c = generic_separator; - } - } - return result; -#else - return detail::fromUtf8>(_path, a); -#endif -} - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE std::string path::generic_string() const -{ -#ifdef GHC_OS_WINDOWS - return generic_string(); -#else - return _path; -#endif -} - -GHC_INLINE std::wstring path::generic_wstring() const -{ -#ifdef GHC_OS_WINDOWS - return generic_string(); -#else - return detail::fromUtf8(_path); -#endif -} // namespace filesystem - -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) -GHC_INLINE std::u8string path::generic_u8string() const -{ -#ifdef GHC_OS_WINDOWS - return generic_string(); -#else - return std::u8string(reinterpret_cast(_path.c_str())); -#endif -} -#else -GHC_INLINE std::string path::generic_u8string() const -{ -#ifdef GHC_OS_WINDOWS - return generic_string(); -#else - return _path; -#endif -} -#endif - -GHC_INLINE std::u16string path::generic_u16string() const -{ -#ifdef GHC_OS_WINDOWS - return generic_string(); -#else - return detail::fromUtf8(_path); -#endif -} - -GHC_INLINE std::u32string path::generic_u32string() const -{ -#ifdef GHC_OS_WINDOWS - return generic_string(); -#else - return detail::fromUtf8(_path); -#endif -} - -//----------------------------------------------------------------------------- -// [fs.path.compare] compare -GHC_INLINE int path::compare(const path& p) const noexcept -{ -#ifdef LWG_2936_BEHAVIOUR - auto rnl1 = root_name_length(); - auto rnl2 = p.root_name_length(); -#ifdef GHC_OS_WINDOWS - auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2); -#else - auto rnc = _path.compare(0, rnl1, p._path, 0, (std::min(rnl1, rnl2))); -#endif - if (rnc) { - return rnc; - } - bool hrd1 = has_root_directory(), hrd2 = p.has_root_directory(); - if (hrd1 != hrd2) { - return hrd1 ? 1 : -1; - } - if (hrd1) { - ++rnl1; - ++rnl2; - } - auto iter1 = _path.begin() + static_cast(rnl1); - auto iter2 = p._path.begin() + static_cast(rnl2); - while (iter1 != _path.end() && iter2 != p._path.end() && *iter1 == *iter2) { - ++iter1; - ++iter2; - } - if (iter1 == _path.end()) { - return iter2 == p._path.end() ? 0 : -1; - } - if (iter2 == p._path.end()) { - return 1; - } - if (*iter1 == preferred_separator) { - return -1; - } - if (*iter2 == preferred_separator) { - return 1; - } - return *iter1 < *iter2 ? -1 : 1; -#else // LWG_2936_BEHAVIOUR -#ifdef GHC_OS_WINDOWS - auto rnl1 = root_name_length(); - auto rnl2 = p.root_name_length(); - auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2); - if (rnc) { - return rnc; - } - return _path.compare(rnl1, std::string::npos, p._path, rnl2, std::string::npos); -#else - return _path.compare(p._path); -#endif -#endif -} - -GHC_INLINE int path::compare(const string_type& s) const -{ - return compare(path(s)); -} - -#ifdef GHC_WITH_STRING_VIEW -GHC_INLINE int path::compare(basic_string_view s) const -{ - return compare(path(s)); -} -#endif - -GHC_INLINE int path::compare(const value_type* s) const -{ - return compare(path(s)); -} - -//----------------------------------------------------------------------------- -// [fs.path.decompose] decomposition -#ifdef GHC_OS_WINDOWS -GHC_INLINE void path::handle_prefixes() -{ -#if defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) - _prefixLength = 0; - if (_path.length() >= 6 && _path[2] == '?' && std::toupper(static_cast(_path[4])) >= 'A' && std::toupper(static_cast(_path[4])) <= 'Z' && _path[5] == ':') { - if (detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\"))) || detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\??\\")))) { - _prefixLength = 4; - } - } -#endif // GHC_WIN_AUTO_PREFIX_LONG_PATH -} -#endif - -GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept -{ -#ifdef GHC_OS_WINDOWS - if (_path.length() >= _prefixLength + 2 && std::toupper(static_cast(_path[_prefixLength])) >= 'A' && std::toupper(static_cast(_path[_prefixLength])) <= 'Z' && _path[_prefixLength + 1] == ':') { - return 2; - } -#endif - if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator && std::isprint(_path[_prefixLength + 2])) { - impl_string_type::size_type pos = _path.find(preferred_separator, _prefixLength + 3); - if (pos == impl_string_type::npos) { - return _path.length(); - } - else { - return pos; - } - } - return 0; -} - -GHC_INLINE path path::root_name() const -{ - return path(_path.substr(_prefixLength, root_name_length()), native_format); -} - -GHC_INLINE path path::root_directory() const -{ - if (has_root_directory()) { - static const path _root_dir(std::string(1, preferred_separator), native_format); - return _root_dir; - } - return path(); -} - -GHC_INLINE path path::root_path() const -{ - return path(root_name().string() + root_directory().string(), native_format); -} - -GHC_INLINE path path::relative_path() const -{ - auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); - return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format); -} - -GHC_INLINE path path::parent_path() const -{ - auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); - if (rootPathLen < _path.length()) { - if (empty()) { - return path(); - } - else { - auto piter = end(); - auto iter = piter.decrement(_path.end()); - if (iter > _path.begin() + static_cast(rootPathLen) && *iter != preferred_separator) { - --iter; - } - return path(_path.begin(), iter, native_format); - } - } - else { - return *this; - } -} - -GHC_INLINE path path::filename() const -{ - return !has_relative_path() ? path() : path(*--end()); -} - -GHC_INLINE path path::stem() const -{ - impl_string_type fn = filename().native(); - if (fn != "." && fn != "..") { - impl_string_type::size_type pos = fn.rfind('.'); - if (pos != impl_string_type::npos && pos > 0) { - return path{fn.substr(0, pos), native_format}; - } - } - return path{fn, native_format}; -} - -GHC_INLINE path path::extension() const -{ - if (has_relative_path()) { - auto iter = end(); - const auto& fn = *--iter; - impl_string_type::size_type pos = fn._path.rfind('.'); - if (pos != std::string::npos && pos > 0) { - return path(fn._path.substr(pos), native_format); - } - } - return path(); -} - -#ifdef GHC_OS_WINDOWS -namespace detail { -GHC_INLINE bool has_executable_extension(const path& p) -{ - if (p.has_relative_path()) { - auto iter = p.end(); - const auto& fn = *--iter; - auto pos = fn._path.find_last_of('.'); - if (pos == std::string::npos || pos == 0 || fn._path.length() - pos != 3) { - return false; - } - const path::value_type* ext = fn._path.c_str() + pos + 1; - if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) { - return true; - } - } - return false; -} -} // namespace detail -#endif - -//----------------------------------------------------------------------------- -// [fs.path.query] query -GHC_INLINE bool path::empty() const noexcept -{ - return _path.empty(); -} - -GHC_INLINE bool path::has_root_name() const -{ - return root_name_length() > 0; -} - -GHC_INLINE bool path::has_root_directory() const -{ - auto rootLen = _prefixLength + root_name_length(); - return (_path.length() > rootLen && _path[rootLen] == preferred_separator); -} - -GHC_INLINE bool path::has_root_path() const -{ - return has_root_name() || has_root_directory(); -} - -GHC_INLINE bool path::has_relative_path() const -{ - auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); - return rootPathLen < _path.length(); -} - -GHC_INLINE bool path::has_parent_path() const -{ - return !parent_path().empty(); -} - -GHC_INLINE bool path::has_filename() const -{ - return has_relative_path() && !filename().empty(); -} - -GHC_INLINE bool path::has_stem() const -{ - return !stem().empty(); -} - -GHC_INLINE bool path::has_extension() const -{ - return !extension().empty(); -} - -GHC_INLINE bool path::is_absolute() const -{ -#ifdef GHC_OS_WINDOWS - return has_root_name() && has_root_directory(); -#else - return has_root_directory(); -#endif -} - -GHC_INLINE bool path::is_relative() const -{ - return !is_absolute(); -} - -//----------------------------------------------------------------------------- -// [fs.path.gen] generation -GHC_INLINE path path::lexically_normal() const -{ - path dest; - bool lastDotDot = false; - for (string_type s : *this) { - if (s == ".") { - dest /= ""; - continue; - } - else if (s == ".." && !dest.empty()) { - auto root = root_path(); - if (dest == root) { - continue; - } - else if (*(--dest.end()) != "..") { - if (dest._path.back() == preferred_separator) { - dest._path.pop_back(); - } - dest.remove_filename(); - continue; - } - } - if (!(s.empty() && lastDotDot)) { - dest /= s; - } - lastDotDot = s == ".."; - } - if (dest.empty()) { - dest = "."; - } - return dest; -} - -GHC_INLINE path path::lexically_relative(const path& base) const -{ - if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) { - return path(); - } - const_iterator a = begin(), b = base.begin(); - while (a != end() && b != base.end() && *a == *b) { - ++a; - ++b; - } - if (a == end() && b == base.end()) { - return path("."); - } - int count = 0; - for (const auto& element : input_iterator_range(b, base.end())) { - if (element != "." && element != "" && element != "..") { - ++count; - } - else if (element == "..") { - --count; - } - } - if (count < 0) { - return path(); - } - path result; - for (int i = 0; i < count; ++i) { - result /= ".."; - } - for (const auto& element : input_iterator_range(a, end())) { - result /= element; - } - return result; -} - -GHC_INLINE path path::lexically_proximate(const path& base) const -{ - path result = lexically_relative(base); - return result.empty() ? *this : result; -} - -//----------------------------------------------------------------------------- -// [fs.path.itr] iterators -GHC_INLINE path::iterator::iterator() {} - -GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos) - : _first(p._path.begin()) - , _last(p._path.end()) - , _prefix(_first + static_cast(p._prefixLength)) - , _root(p.has_root_directory() ? _first + static_cast(p._prefixLength + p.root_name_length()) : _last) - , _iter(pos) -{ - if(pos != _last) { - updateCurrent(); - } -} - -GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const -{ - path::impl_string_type::const_iterator i = pos; - bool fromStart = i == _first || i == _prefix; - if (i != _last) { - if (fromStart && i == _first && _prefix > _first) { - i = _prefix; - } - else if (*i++ == preferred_separator) { - // we can only sit on a slash if it is a network name or a root - if (i != _last && *i == preferred_separator) { - if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) { - // leadind double slashes detected, treat this and the - // following until a slash as one unit - i = std::find(++i, _last, preferred_separator); - } - else { - // skip redundant slashes - while (i != _last && *i == preferred_separator) { - ++i; - } - } - } - } - else { - if (fromStart && i != _last && *i == ':') { - ++i; - } - else { - i = std::find(i, _last, preferred_separator); - } - } - } - return i; -} - -GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const -{ - path::impl_string_type::const_iterator i = pos; - if (i != _first) { - --i; - // if this is now the root slash or the trailing slash, we are done, - // else check for network name - if (i != _root && (pos != _last || *i != preferred_separator)) { -#ifdef GHC_OS_WINDOWS - static const impl_string_type seps = GHC_PLATFORM_LITERAL("\\:"); - i = std::find_first_of(std::reverse_iterator(i), std::reverse_iterator(_first), seps.begin(), seps.end()).base(); - if (i > _first && *i == ':') { - i++; - } -#else - i = std::find(std::reverse_iterator(i), std::reverse_iterator(_first), preferred_separator).base(); -#endif - // Now we have to check if this is a network name - if (i - _first == 2 && *_first == preferred_separator && *(_first + 1) == preferred_separator) { - i -= 2; - } - } - } - return i; -} - -GHC_INLINE void path::iterator::updateCurrent() -{ - if ((_iter == _last) || (_iter != _first && _iter != _last && (*_iter == preferred_separator && _iter != _root) && (_iter + 1 == _last))) { - _current.clear(); - } - else { - _current.assign(_iter, increment(_iter)); - } -} - -GHC_INLINE path::iterator& path::iterator::operator++() -{ - _iter = increment(_iter); - while (_iter != _last && // we didn't reach the end - _iter != _root && // this is not a root position - *_iter == preferred_separator && // we are on a separator - (_iter + 1) != _last // the slash is not the last char - ) { - ++_iter; - } - updateCurrent(); - return *this; -} - -GHC_INLINE path::iterator path::iterator::operator++(int) -{ - path::iterator i{*this}; - ++(*this); - return i; -} - -GHC_INLINE path::iterator& path::iterator::operator--() -{ - _iter = decrement(_iter); - updateCurrent(); - return *this; -} - -GHC_INLINE path::iterator path::iterator::operator--(int) -{ - auto i = *this; - --(*this); - return i; -} - -GHC_INLINE bool path::iterator::operator==(const path::iterator& other) const -{ - return _iter == other._iter; -} - -GHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const -{ - return _iter != other._iter; -} - -GHC_INLINE path::iterator::reference path::iterator::operator*() const -{ - return _current; -} - -GHC_INLINE path::iterator::pointer path::iterator::operator->() const -{ - return &_current; -} - -GHC_INLINE path::iterator path::begin() const -{ - return iterator(*this, _path.begin()); -} - -GHC_INLINE path::iterator path::end() const -{ - return iterator(*this, _path.end()); -} - -//----------------------------------------------------------------------------- -// [fs.path.nonmember] path non-member functions -GHC_INLINE void swap(path& lhs, path& rhs) noexcept -{ - swap(lhs._path, rhs._path); -} - -GHC_INLINE size_t hash_value(const path& p) noexcept -{ - return std::hash()(p.generic_string()); -} - -#ifdef GHC_HAS_THREEWAY_COMP -GHC_INLINE std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept -{ - return lhs.compare(rhs) <=> 0; -} -#endif - -GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept -{ - return lhs.compare(rhs) == 0; -} - -GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept -{ - return !(lhs == rhs); -} - -GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept -{ - return lhs.compare(rhs) < 0; -} - -GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept -{ - return lhs.compare(rhs) <= 0; -} - -GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept -{ - return lhs.compare(rhs) > 0; -} - -GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept -{ - return lhs.compare(rhs) >= 0; -} - -GHC_INLINE path operator/(const path& lhs, const path& rhs) -{ - path result(lhs); - result /= rhs; - return result; -} - -#endif // GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// [fs.path.io] path inserter and extractor -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const path& p) -{ - os << "\""; - auto ps = p.string(); - for (auto c : ps) { - if (c == '"' || c == '\\') { - os << '\\'; - } - os << c; - } - os << "\""; - return os; -} - -template -inline std::basic_istream& operator>>(std::basic_istream& is, path& p) -{ - std::basic_string tmp; - charT c; - is >> c; - if (c == '"') { - auto sf = is.flags(); - is >> std::noskipws; - while (is) { - auto c2 = is.get(); - if (is) { - if (c2 == '\\') { - c2 = is.get(); - if (is) { - tmp += static_cast(c2); - } - } - else if (c2 == '"') { - break; - } - else { - tmp += static_cast(c2); - } - } - } - if ((sf & std::ios_base::skipws) == std::ios_base::skipws) { - is >> std::skipws; - } - p = path(tmp); - } - else { - is >> tmp; - p = path(static_cast(c) + tmp); - } - return is; -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// [fs.class.filesystem_error] Class filesystem_error -GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec) - : std::system_error(ec, what_arg) - , _what_arg(what_arg) - , _ec(ec) -{ -} - -GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec) - : std::system_error(ec, what_arg) - , _what_arg(what_arg) - , _ec(ec) - , _p1(p1) -{ - if (!_p1.empty()) { - _what_arg += ": '" + _p1.string() + "'"; - } -} - -GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec) - : std::system_error(ec, what_arg) - , _what_arg(what_arg) - , _ec(ec) - , _p1(p1) - , _p2(p2) -{ - if (!_p1.empty()) { - _what_arg += ": '" + _p1.string() + "'"; - } - if (!_p2.empty()) { - _what_arg += ", '" + _p2.string() + "'"; - } -} - -GHC_INLINE const path& filesystem_error::path1() const noexcept -{ - return _p1; -} - -GHC_INLINE const path& filesystem_error::path2() const noexcept -{ - return _p2; -} - -GHC_INLINE const char* filesystem_error::what() const noexcept -{ - return _what_arg.c_str(); -} - -//----------------------------------------------------------------------------- -// [fs.op.funcs] filesystem operations -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path absolute(const path& p) -{ - std::error_code ec; - path result = absolute(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE path absolute(const path& p, std::error_code& ec) -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (p.empty()) { - return absolute(current_path(ec), ec) / ""; - } - ULONG size = ::GetFullPathNameW(GHC_NATIVEWP(p), 0, 0, 0); - if (size) { - std::vector buf(size, 0); - ULONG s2 = GetFullPathNameW(GHC_NATIVEWP(p), size, buf.data(), nullptr); - if (s2 && s2 < size) { - path result = path(std::wstring(buf.data(), s2)); - if (p.filename() == ".") { - result /= "."; - } - return result; - } - } - ec = detail::make_system_error(); - return path(); -#else - path base = current_path(ec); - if (!ec) { - if (p.empty()) { - return base / p; - } - if (p.has_root_name()) { - if (p.has_root_directory()) { - return p; - } - else { - return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path(); - } - } - else { - if (p.has_root_directory()) { - return base.root_name() / p; - } - else { - return base / p; - } - } - } - ec = detail::make_system_error(); - return path(); -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path canonical(const path& p) -{ - std::error_code ec; - auto result = canonical(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE path canonical(const path& p, std::error_code& ec) -{ - if (p.empty()) { - ec = detail::make_error_code(detail::portable_error::not_found); - return path(); - } - path work = p.is_absolute() ? p : absolute(p, ec); - path result; - - auto fs = status(work, ec); - if (ec) { - return path(); - } - if (fs.type() == file_type::not_found) { - ec = detail::make_error_code(detail::portable_error::not_found); - return path(); - } - bool redo; - do { - auto rootPathLen = work._prefixLength + work.root_name_length() + (work.has_root_directory() ? 1 : 0); - redo = false; - result.clear(); - for (auto pe : work) { - if (pe.empty() || pe == ".") { - continue; - } - else if (pe == "..") { - result = result.parent_path(); - continue; - } - else if ((result / pe).string().length() <= rootPathLen) { - result /= pe; - continue; - } - auto sls = symlink_status(result / pe, ec); - if (ec) { - return path(); - } - if (is_symlink(sls)) { - redo = true; - auto target = read_symlink(result / pe, ec); - if (ec) { - return path(); - } - if (target.is_absolute()) { - result = target; - continue; - } - else { - result /= target; - continue; - } - } - else { - result /= pe; - } - } - work = result; - } while (redo); - ec.clear(); - return result; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void copy(const path& from, const path& to) -{ - copy(from, to, copy_options::none); -} - -GHC_INLINE void copy(const path& from, const path& to, copy_options options) -{ - std::error_code ec; - copy(from, to, options, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); - } -} -#endif - -GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept -{ - copy(from, to, copy_options::none, ec); -} - -GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept -{ - std::error_code tec; - file_status fs_from, fs_to; - ec.clear(); - if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) { - fs_from = symlink_status(from, ec); - } - else { - fs_from = status(from, ec); - } - if (!exists(fs_from)) { - if (!ec) { - ec = detail::make_error_code(detail::portable_error::not_found); - } - return; - } - if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) { - fs_to = symlink_status(to, tec); - } - else { - fs_to = status(to, tec); - } - if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - } - else if (is_symlink(fs_from)) { - if ((options & copy_options::skip_symlinks) == copy_options::none) { - if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) { - copy_symlink(from, to, ec); - } - else { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - } - } - } - else if (is_regular_file(fs_from)) { - if ((options & copy_options::directories_only) == copy_options::none) { - if ((options & copy_options::create_symlinks) != copy_options::none) { - create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec); - } -#ifndef GHC_OS_WEB - else if ((options & copy_options::create_hard_links) != copy_options::none) { - create_hard_link(from, to, ec); - } -#endif - else if (is_directory(fs_to)) { - copy_file(from, to / from.filename(), options, ec); - } - else { - copy_file(from, to, options, ec); - } - } - } -#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) { - return; - } - } - for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) { - if (!ec) { - copy(iter->path(), to / iter->path().filename(), options | static_cast(0x8000), ec); - } - if (ec) { - return; - } - } - } - return; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool copy_file(const path& from, const path& to) -{ - return copy_file(from, to, copy_options::none); -} - -GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option) -{ - std::error_code ec; - auto result = copy_file(from, to, option, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); - } - return result; -} -#endif - -GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept -{ - return copy_file(from, to, copy_options::none, ec); -} - -GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept -{ - std::error_code tecf, tect; - auto sf = status(from, tecf); - auto st = status(to, tect); - bool overwrite = false; - ec.clear(); - if (!is_regular_file(sf)) { - ec = tecf; - return false; - } - if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) { - ec = tect ? tect : detail::make_error_code(detail::portable_error::exists); - return false; - } - if (exists(st)) { - if ((options & copy_options::update_existing) == copy_options::update_existing) { - auto from_time = last_write_time(from, ec); - if (ec) { - ec = detail::make_system_error(); - return false; - } - auto to_time = last_write_time(to, ec); - if (ec) { - ec = detail::make_system_error(); - return false; - } - if (from_time <= to_time) { - return false; - } - } - overwrite = true; - } -#ifdef GHC_OS_WINDOWS - if (!::CopyFileW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), !overwrite)) { - ec = detail::make_system_error(); - return false; - } - return true; -#else - std::vector buffer(16384, '\0'); - int in = -1, out = -1; - if ((in = ::open(from.c_str(), O_RDONLY)) < 0) { - ec = detail::make_system_error(); - return false; - } - int mode = O_CREAT | O_WRONLY | O_TRUNC; - if (!overwrite) { - mode |= O_EXCL; - } - if ((out = ::open(to.c_str(), mode, static_cast(sf.permissions() & perms::all))) < 0) { - ec = detail::make_system_error(); - ::close(in); - return false; - } - ssize_t br, bw; - while ((br = ::read(in, buffer.data(), buffer.size())) > 0) { - ssize_t offset = 0; - do { - if ((bw = ::write(out, buffer.data() + offset, static_cast(br))) > 0) { - br -= bw; - offset += bw; - } - else if (bw < 0) { - ec = detail::make_system_error(); - ::close(in); - ::close(out); - return false; - } - } while (br); - } - ::close(in); - ::close(out); - return true; -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink) -{ - std::error_code ec; - copy_symlink(existing_symlink, new_symlink, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec); - } -} -#endif - -GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept -{ - ec.clear(); - auto to = read_symlink(existing_symlink, ec); - if (!ec) { - if (exists(to, ec) && is_directory(to, ec)) { - create_directory_symlink(to, new_symlink, ec); - } - else { - create_symlink(to, new_symlink, ec); - } - } -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool create_directories(const path& p) -{ - std::error_code ec; - auto result = create_directories(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept -{ - path current; - ec.clear(); - bool didCreate = false; - auto rootPathLen = p._prefixLength + p.root_name_length() + (p.has_root_directory() ? 1 : 0); - current = p.native().substr(0, rootPathLen); - path folders(p._path.substr(rootPathLen)); - for (path::string_type part : folders) { - current /= part; - std::error_code tec; - auto fs = status(current, tec); - if (tec && fs.type() != file_type::not_found) { - ec = tec; - return false; - } - if (!exists(fs)) { - create_directory(current, ec); - if (ec) { - std::error_code tmp_ec; - if (is_directory(current, tmp_ec)) { - ec.clear(); - } - else { - return false; - } - } - didCreate = true; - } -#ifndef LWG_2935_BEHAVIOUR - else if (!is_directory(fs)) { - ec = detail::make_error_code(detail::portable_error::exists); - return false; - } -#endif - } - return didCreate; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool create_directory(const path& p) -{ - std::error_code ec; - auto result = create_directory(p, path(), ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept -{ - return create_directory(p, path(), ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool create_directory(const path& p, const path& attributes) -{ - std::error_code ec; - auto result = create_directory(p, attributes, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept -{ - std::error_code tec; - ec.clear(); - auto fs = status(p, tec); -#ifdef LWG_2935_BEHAVIOUR - if (status_known(fs) && exists(fs)) { - return false; - } -#else - if (status_known(fs) && exists(fs) && is_directory(fs)) { - return false; - } -#endif -#ifdef GHC_OS_WINDOWS - if (!attributes.empty()) { - if (!::CreateDirectoryExW(GHC_NATIVEWP(attributes), GHC_NATIVEWP(p), NULL)) { - ec = detail::make_system_error(); - return false; - } - } - else if (!::CreateDirectoryW(GHC_NATIVEWP(p), NULL)) { - ec = detail::make_system_error(); - return false; - } -#else - ::mode_t attribs = static_cast(perms::all); - if (!attributes.empty()) { - struct ::stat fileStat; - if (::stat(attributes.c_str(), &fileStat) != 0) { - ec = detail::make_system_error(); - return false; - } - attribs = fileStat.st_mode; - } - if (::mkdir(p.c_str(), attribs) != 0) { - ec = detail::make_system_error(); - return false; - } -#endif - return true; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink) -{ - std::error_code ec; - create_directory_symlink(to, new_symlink, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); - } -} -#endif - -GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept -{ - detail::create_symlink(to, new_symlink, true, ec); -} - -#ifndef GHC_OS_WEB -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link) -{ - std::error_code ec; - create_hard_link(to, new_hard_link, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec); - } -} -#endif - -GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept -{ - detail::create_hardlink(to, new_hard_link, ec); -} -#endif - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void create_symlink(const path& to, const path& new_symlink) -{ - std::error_code ec; - create_symlink(to, new_symlink, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); - } -} -#endif - -GHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept -{ - detail::create_symlink(to, new_symlink, false, ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path current_path() -{ - std::error_code ec; - auto result = current_path(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), ec); - } - return result; -} -#endif - -GHC_INLINE path current_path(std::error_code& ec) -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - DWORD pathlen = ::GetCurrentDirectoryW(0, 0); - std::unique_ptr buffer(new wchar_t[size_t(pathlen) + 1]); - if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) { - ec = detail::make_system_error(); - return path(); - } - return path(std::wstring(buffer.get()), path::native_format); -#else - size_t pathlen = static_cast(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX))); - std::unique_ptr buffer(new char[pathlen + 1]); - if (::getcwd(buffer.get(), pathlen) == nullptr) { - ec = detail::make_system_error(); - return path(); - } - return path(buffer.get()); -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void current_path(const path& p) -{ - std::error_code ec; - current_path(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} -#endif - -GHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (!::SetCurrentDirectoryW(GHC_NATIVEWP(p))) { - ec = detail::make_system_error(); - } -#else - if (::chdir(p.string().c_str()) == -1) { - ec = detail::make_system_error(); - } -#endif -} - -GHC_INLINE bool exists(file_status s) noexcept -{ - return status_known(s) && s.type() != file_type::not_found; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool exists(const path& p) -{ - return exists(status(p)); -} -#endif - -GHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept -{ - file_status s = status(p, ec); - if (status_known(s)) { - ec.clear(); - } - return exists(s); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool equivalent(const path& p1, const path& p2) -{ - std::error_code ec; - bool result = equivalent(p1, p2, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec); - } - return result; -} -#endif - -GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - std::shared_ptr file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - auto e1 = ::GetLastError(); - std::shared_ptr file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) { -#ifdef LWG_2937_BEHAVIOUR - ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); -#else - if (file1 == file2) { - ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); - } -#endif - return false; - } - BY_HANDLE_FILE_INFORMATION inf1, inf2; - if (!::GetFileInformationByHandle(file1.get(), &inf1)) { - ec = detail::make_system_error(); - return false; - } - if (!::GetFileInformationByHandle(file2.get(), &inf2)) { - ec = detail::make_system_error(); - return false; - } - return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow && - inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber; -#else - struct ::stat s1, s2; - auto rc1 = ::stat(p1.c_str(), &s1); - auto e1 = errno; - auto rc2 = ::stat(p2.c_str(), &s2); - if (rc1 || rc2) { -#ifdef LWG_2937_BEHAVIOUR - ec = detail::make_system_error(e1 ? e1 : errno); -#else - if (rc1 && rc2) { - ec = detail::make_system_error(e1 ? e1 : errno); - } -#endif - return false; - } - return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE uintmax_t file_size(const path& p) -{ - std::error_code ec; - auto result = file_size(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { - ec = detail::make_system_error(); - return static_cast(-1); - } - return static_cast(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow; -#else - struct ::stat fileStat; - if (::stat(p.c_str(), &fileStat) == -1) { - ec = detail::make_system_error(); - return static_cast(-1); - } - return static_cast(fileStat.st_size); -#endif -} - -#ifndef GHC_OS_WEB -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE uintmax_t hard_link_count(const path& p) -{ - std::error_code ec; - auto result = hard_link_count(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - uintmax_t result = static_cast(-1); - std::shared_ptr file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - BY_HANDLE_FILE_INFORMATION inf; - if (file.get() == INVALID_HANDLE_VALUE) { - ec = detail::make_system_error(); - } - else { - if (!::GetFileInformationByHandle(file.get(), &inf)) { - ec = detail::make_system_error(); - } - else { - result = inf.nNumberOfLinks; - } - } - return result; -#else - uintmax_t result = 0; - file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr); - if (fs.type() == file_type::not_found) { - ec = detail::make_error_code(detail::portable_error::not_found); - } - return ec ? static_cast(-1) : result; -#endif -} -#endif - -GHC_INLINE bool is_block_file(file_status s) noexcept -{ - return s.type() == file_type::block; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_block_file(const path& p) -{ - return is_block_file(status(p)); -} -#endif - -GHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept -{ - return is_block_file(status(p, ec)); -} - -GHC_INLINE bool is_character_file(file_status s) noexcept -{ - return s.type() == file_type::character; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_character_file(const path& p) -{ - return is_character_file(status(p)); -} -#endif - -GHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept -{ - return is_character_file(status(p, ec)); -} - -GHC_INLINE bool is_directory(file_status s) noexcept -{ - return s.type() == file_type::directory; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_directory(const path& p) -{ - return is_directory(status(p)); -} -#endif - -GHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept -{ - return is_directory(status(p, ec)); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_empty(const path& p) -{ - if (is_directory(p)) { - return directory_iterator(p) == directory_iterator(); - } - else { - return file_size(p) == 0; - } -} -#endif - -GHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept -{ - auto fs = status(p, ec); - if (ec) { - return false; - } - if (is_directory(fs)) { - directory_iterator iter(p, ec); - if (ec) { - return false; - } - return iter == directory_iterator(); - } - else { - auto sz = file_size(p, ec); - if (ec) { - return false; - } - return sz == 0; - } -} - -GHC_INLINE bool is_fifo(file_status s) noexcept -{ - return s.type() == file_type::fifo; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_fifo(const path& p) -{ - return is_fifo(status(p)); -} -#endif - -GHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept -{ - return is_fifo(status(p, ec)); -} - -GHC_INLINE bool is_other(file_status s) noexcept -{ - return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_other(const path& p) -{ - return is_other(status(p)); -} -#endif - -GHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept -{ - return is_other(status(p, ec)); -} - -GHC_INLINE bool is_regular_file(file_status s) noexcept -{ - return s.type() == file_type::regular; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_regular_file(const path& p) -{ - return is_regular_file(status(p)); -} -#endif - -GHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept -{ - return is_regular_file(status(p, ec)); -} - -GHC_INLINE bool is_socket(file_status s) noexcept -{ - return s.type() == file_type::socket; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_socket(const path& p) -{ - return is_socket(status(p)); -} -#endif - -GHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept -{ - return is_socket(status(p, ec)); -} - -GHC_INLINE bool is_symlink(file_status s) noexcept -{ - return s.type() == file_type::symlink; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool is_symlink(const path& p) -{ - return is_symlink(symlink_status(p)); -} -#endif - -GHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept -{ - return is_symlink(symlink_status(p, ec)); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE file_time_type last_write_time(const path& p) -{ - std::error_code ec; - auto result = last_write_time(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept -{ - time_t result = 0; - ec.clear(); - file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result); - return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void last_write_time(const path& p, file_time_type new_time) -{ - std::error_code ec; - last_write_time(p, new_time, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} -#endif - -GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept -{ - ec.clear(); - auto d = new_time.time_since_epoch(); -#ifdef GHC_OS_WINDOWS - std::shared_ptr file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle); - FILETIME ft; - auto tt = std::chrono::duration_cast(d).count() * 10 + 116444736000000000; - ft.dwLowDateTime = static_cast(tt); - ft.dwHighDateTime = static_cast(tt >> 32); - if (!::SetFileTime(file.get(), 0, 0, &ft)) { - ec = detail::make_system_error(); - } -#elif defined(GHC_OS_MACOS) -#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED -#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 - struct ::stat fs; - if (::stat(p.c_str(), &fs) == 0) { - struct ::timeval tv[2]; - tv[0].tv_sec = fs.st_atimespec.tv_sec; - tv[0].tv_usec = static_cast(fs.st_atimespec.tv_nsec / 1000); - tv[1].tv_sec = std::chrono::duration_cast(d).count(); - tv[1].tv_usec = static_cast(std::chrono::duration_cast(d).count() % 1000000); - if (::utimes(p.c_str(), tv) == 0) { - return; - } - } - ec = detail::make_system_error(); - return; -#else - struct ::timespec times[2]; - times[0].tv_sec = 0; - times[0].tv_nsec = UTIME_OMIT; - times[1].tv_sec = std::chrono::duration_cast(d).count(); - times[1].tv_nsec = 0; // std::chrono::duration_cast(d).count() % 1000000000; - if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { - ec = detail::make_system_error(); - } - return; -#endif -#endif -#else -#ifndef UTIME_OMIT -#define UTIME_OMIT ((1l << 30) - 2l) -#endif - struct ::timespec times[2]; - times[0].tv_sec = 0; - times[0].tv_nsec = UTIME_OMIT; - times[1].tv_sec = static_cast(std::chrono::duration_cast(d).count()); - times[1].tv_nsec = static_cast(std::chrono::duration_cast(d).count() % 1000000000); -#if defined(__ANDROID_API__) && __ANDROID_API__ < 12 - if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { -#else - if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { -#endif - ec = detail::make_system_error(); - } - return; -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void permissions(const path& p, perms prms, perm_options opts) -{ - std::error_code ec; - permissions(p, prms, opts, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} -#endif - -GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept -{ - permissions(p, prms, perm_options::replace, ec); -} - -GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept -{ - if (static_cast(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - return; - } - auto fs = symlink_status(p, ec); - if ((opts & perm_options::replace) != perm_options::replace) { - if ((opts & perm_options::add) == perm_options::add) { - prms = fs.permissions() | prms; - } - else { - prms = fs.permissions() & ~prms; - } - } -#ifdef GHC_OS_WINDOWS -#ifdef __GNUC__ - auto oldAttr = GetFileAttributesW(GHC_NATIVEWP(p)); - if (oldAttr != INVALID_FILE_ATTRIBUTES) { - DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY; - if (oldAttr == newAttr || SetFileAttributesW(GHC_NATIVEWP(p), newAttr)) { - return; - } - } - ec = detail::make_system_error(); -#else - int mode = 0; - if ((prms & perms::owner_read) == perms::owner_read) { - mode |= _S_IREAD; - } - if ((prms & perms::owner_write) == perms::owner_write) { - mode |= _S_IWRITE; - } - if (::_wchmod(p.wstring().c_str(), mode) != 0) { - ec = detail::make_system_error(); - } -#endif -#else - if ((opts & perm_options::nofollow) != perm_options::nofollow) { - if (::chmod(p.c_str(), static_cast(prms)) != 0) { - ec = detail::make_system_error(); - } - } -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path proximate(const path& p, std::error_code& ec) -{ - auto cp = current_path(ec); - if (!ec) { - return proximate(p, cp, ec); - } - return path(); -} -#endif - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path proximate(const path& p, const path& base) -{ - return weakly_canonical(p).lexically_proximate(weakly_canonical(base)); -} -#endif - -GHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec) -{ - return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec)); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path read_symlink(const path& p) -{ - std::error_code ec; - auto result = read_symlink(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE path read_symlink(const path& p, std::error_code& ec) -{ - file_status fs = symlink_status(p, ec); - if (fs.type() != file_type::symlink) { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - return path(); - } - auto result = detail::resolveSymlink(p, ec); - return ec ? path() : result; -} - -GHC_INLINE path relative(const path& p, std::error_code& ec) -{ - return relative(p, current_path(ec), ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path relative(const path& p, const path& base) -{ - return weakly_canonical(p).lexically_relative(weakly_canonical(base)); -} -#endif - -GHC_INLINE path relative(const path& p, const path& base, std::error_code& ec) -{ - return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec)); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool remove(const path& p) -{ - std::error_code ec; - auto result = remove(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS -#ifdef GHC_USE_WCHAR_T - auto cstr = p.c_str(); -#else - std::wstring np = detail::fromUtf8(p.u8string()); - auto cstr = np.c_str(); -#endif - DWORD attr = GetFileAttributesW(cstr); - if (attr == INVALID_FILE_ATTRIBUTES) { - auto error = ::GetLastError(); - if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) { - return false; - } - ec = detail::make_system_error(error); - } - else if(attr & FILE_ATTRIBUTE_READONLY) { - auto new_attr = attr & ~static_cast(FILE_ATTRIBUTE_READONLY); - if(!SetFileAttributesW(cstr, new_attr)) { - auto error = ::GetLastError(); - ec = detail::make_system_error(error); - } - } - if (!ec) { - if (attr & FILE_ATTRIBUTE_DIRECTORY) { - if (!RemoveDirectoryW(cstr)) { - ec = detail::make_system_error(); - } - } - else { - if (!DeleteFileW(cstr)) { - ec = detail::make_system_error(); - } - } - } -#else - if (::remove(p.c_str()) == -1) { - auto error = errno; - if (error == ENOENT) { - return false; - } - ec = detail::make_system_error(); - } -#endif - return ec ? false : true; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE uintmax_t remove_all(const path& p) -{ - std::error_code ec; - auto result = remove_all(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); - uintmax_t count = 0; - if (p == "/") { - ec = detail::make_error_code(detail::portable_error::not_supported); - return static_cast(-1); - } - std::error_code tec; - auto fs = status(p, tec); - if (exists(fs) && is_directory(fs)) { - for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) { - if (ec && !detail::is_not_found_error(ec)) { - break; - } - bool is_symlink_result = iter->is_symlink(ec); - if (ec) - return static_cast(-1); - if (!is_symlink_result && iter->is_directory(ec)) { - count += remove_all(iter->path(), ec); - if (ec) { - return static_cast(-1); - } - } - else { - if (!ec) { - remove(iter->path(), ec); - } - if (ec) { - return static_cast(-1); - } - ++count; - } - } - } - if (!ec) { - if (remove(p, ec)) { - ++count; - } - } - if (ec) { - return static_cast(-1); - } - return count; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void rename(const path& from, const path& to) -{ - std::error_code ec; - rename(from, to, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); - } -} -#endif - -GHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (from != to) { - if (!MoveFileExW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), (DWORD)MOVEFILE_REPLACE_EXISTING)) { - ec = detail::make_system_error(); - } - } -#else - if (from != to) { - if (::rename(from.c_str(), to.c_str()) != 0) { - ec = detail::make_system_error(); - } - } -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void resize_file(const path& p, uintmax_t size) -{ - std::error_code ec; - resize_file(p, size, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} -#endif - -GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - LARGE_INTEGER lisize; - lisize.QuadPart = static_cast(size); - if (lisize.QuadPart < 0) { -#ifdef ERROR_FILE_TOO_LARGE - ec = detail::make_system_error(ERROR_FILE_TOO_LARGE); -#else - ec = detail::make_system_error(223); -#endif - return; - } - std::shared_ptr file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle); - if (file.get() == INVALID_HANDLE_VALUE) { - ec = detail::make_system_error(); - } - else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { - ec = detail::make_system_error(); - } -#else - if (::truncate(p.c_str(), static_cast(size)) != 0) { - ec = detail::make_system_error(); - } -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE space_info space(const path& p) -{ - std::error_code ec; - auto result = space(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - ULARGE_INTEGER freeBytesAvailableToCaller = {{ 0, 0 }}; - ULARGE_INTEGER totalNumberOfBytes = {{ 0, 0 }}; - ULARGE_INTEGER totalNumberOfFreeBytes = {{ 0, 0 }}; - if (!GetDiskFreeSpaceExW(GHC_NATIVEWP(p), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { - ec = detail::make_system_error(); - return {static_cast(-1), static_cast(-1), static_cast(-1)}; - } - return {static_cast(totalNumberOfBytes.QuadPart), static_cast(totalNumberOfFreeBytes.QuadPart), static_cast(freeBytesAvailableToCaller.QuadPart)}; -#else - struct ::statvfs sfs; - if (::statvfs(p.c_str(), &sfs) != 0) { - ec = detail::make_system_error(); - return {static_cast(-1), static_cast(-1), static_cast(-1)}; - } - return {static_cast(sfs.f_blocks * sfs.f_frsize), static_cast(sfs.f_bfree * sfs.f_frsize), static_cast(sfs.f_bavail * sfs.f_frsize)}; -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE file_status status(const path& p) -{ - std::error_code ec; - auto result = status(p, ec); - if (result.type() == file_type::none) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept -{ - return detail::status_ex(p, ec); -} - -GHC_INLINE bool status_known(file_status s) noexcept -{ - return s.type() != file_type::none; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE file_status symlink_status(const path& p) -{ - std::error_code ec; - auto result = symlink_status(p, ec); - if (result.type() == file_type::none) { - throw filesystem_error(detail::systemErrorText(ec.value()), ec); - } - return result; -} -#endif - -GHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept -{ - return detail::symlink_status_ex(p, ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path temp_directory_path() -{ - std::error_code ec; - path result = temp_directory_path(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), ec); - } - return result; -} -#endif - -GHC_INLINE path temp_directory_path(std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - wchar_t buffer[512]; - auto rc = GetTempPathW(511, buffer); - if (!rc || rc > 511) { - ec = detail::make_system_error(); - return path(); - } - return path(std::wstring(buffer)); -#else - static const char* temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr}; - const char* temp_path = nullptr; - for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) { - temp_path = std::getenv(*temp_name); - if (temp_path) { - return path(temp_path); - } - } - return path("/tmp"); -#endif -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE path weakly_canonical(const path& p) -{ - std::error_code ec; - auto result = weakly_canonical(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} -#endif - -GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept -{ - path result; - ec.clear(); - bool scan = true; - for (auto pe : p) { - if (scan) { - std::error_code tec; - if (exists(result / pe, tec)) { - result /= pe; - } - else { - if (ec) { - return path(); - } - scan = false; - if (!result.empty()) { - result = canonical(result, ec) / pe; - if (ec) { - break; - } - } - else { - result /= pe; - } - } - } - else { - result /= pe; - } - } - if (scan) { - if (!result.empty()) { - result = canonical(result, ec); - } - } - return ec ? path() : result.lexically_normal(); -} - -//----------------------------------------------------------------------------- -// [fs.class.file_status] class file_status -// [fs.file_status.cons] constructors and destructor -GHC_INLINE file_status::file_status() noexcept - : file_status(file_type::none) -{ -} - -GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept - : _type(ft) - , _perms(prms) -{ -} - -GHC_INLINE file_status::file_status(const file_status& other) noexcept - : _type(other._type) - , _perms(other._perms) -{ -} - -GHC_INLINE file_status::file_status(file_status&& other) noexcept - : _type(other._type) - , _perms(other._perms) -{ -} - -GHC_INLINE file_status::~file_status() {} - -// assignments: -GHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept -{ - _type = rhs._type; - _perms = rhs._perms; - return *this; -} - -GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept -{ - _type = rhs._type; - _perms = rhs._perms; - return *this; -} - -// [fs.file_status.mods] modifiers -GHC_INLINE void file_status::type(file_type ft) noexcept -{ - _type = ft; -} - -GHC_INLINE void file_status::permissions(perms prms) noexcept -{ - _perms = prms; -} - -// [fs.file_status.obs] observers -GHC_INLINE file_type file_status::type() const noexcept -{ - return _type; -} - -GHC_INLINE perms file_status::permissions() const noexcept -{ - return _perms; -} - -//----------------------------------------------------------------------------- -// [fs.class.directory_entry] class directory_entry -// [fs.dir.entry.cons] constructors and destructor -// directory_entry::directory_entry() noexcept = default; -// directory_entry::directory_entry(const directory_entry&) = default; -// directory_entry::directory_entry(directory_entry&&) noexcept = default; -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) - : _path(p) - , _file_size(static_cast(-1)) -#ifndef GHC_OS_WINDOWS - , _hard_link_count(static_cast(-1)) -#endif - , _last_write_time(0) -{ - refresh(); -} -#endif - -GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec) - : _path(p) - , _file_size(static_cast(-1)) -#ifndef GHC_OS_WINDOWS - , _hard_link_count(static_cast(-1)) -#endif - , _last_write_time(0) -{ - refresh(ec); -} - -GHC_INLINE directory_entry::~directory_entry() {} - -// assignments: -// directory_entry& directory_entry::operator=(const directory_entry&) = default; -// directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default; - -// [fs.dir.entry.mods] directory_entry modifiers -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void directory_entry::assign(const filesystem::path& p) -{ - _path = p; - refresh(); -} -#endif - -GHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec) -{ - _path = p; - refresh(ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p) -{ - _path.replace_filename(p); - refresh(); -} -#endif - -GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec) -{ - _path.replace_filename(p); - refresh(ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void directory_entry::refresh() -{ - std::error_code ec; - refresh(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec); - } -} -#endif - -GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept -{ -#ifdef GHC_OS_WINDOWS - _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time); -#else - _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time); -#endif -} - -// [fs.dir.entry.obs] directory_entry observers -GHC_INLINE const filesystem::path& directory_entry::path() const noexcept -{ - return _path; -} - -GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept -{ - return _path; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE file_type directory_entry::status_file_type() const -{ - return _status.type() != file_type::none ? _status.type() : filesystem::status(path()).type(); -} -#endif - -GHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept -{ - if(_status.type() != file_type::none) { - ec.clear(); - return _status.type(); - } - return filesystem::status(path(), ec).type(); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::exists() const -{ - return status_file_type() != file_type::not_found; -} -#endif - -GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept -{ - return status_file_type(ec) != file_type::not_found; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_block_file() const -{ - return status_file_type() == file_type::block; -} -#endif -GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept -{ - return status_file_type(ec) == file_type::block; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_character_file() const -{ - return status_file_type() == file_type::character; -} -#endif - -GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept -{ - return status_file_type(ec) == file_type::character; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_directory() const -{ - return status_file_type() == file_type::directory; -} -#endif - -GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept -{ - return status_file_type(ec) == file_type::directory; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_fifo() const -{ - return status_file_type() == file_type::fifo; -} -#endif - -GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept -{ - return status_file_type(ec) == file_type::fifo; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_other() const -{ - auto ft = status_file_type(); - return ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(); -} -#endif - -GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept -{ - auto ft = status_file_type(ec); - bool other = ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(ec); - return !ec && other; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_regular_file() const -{ - return status_file_type() == file_type::regular; -} -#endif - -GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept -{ - return status_file_type(ec) == file_type::regular; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_socket() const -{ - return status_file_type() == file_type::socket; -} -#endif - -GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept -{ - return status_file_type(ec) == file_type::socket; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE bool directory_entry::is_symlink() const -{ - return _symlink_status.type() != file_type::none ? _symlink_status.type() == file_type::symlink : filesystem::is_symlink(symlink_status()); -} -#endif - -GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept -{ - if(_symlink_status.type() != file_type::none) { - ec.clear(); - return _symlink_status.type() == file_type::symlink; - } - return filesystem::is_symlink(symlink_status(ec)); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE uintmax_t directory_entry::file_size() const -{ - if (_file_size != static_cast(-1)) { - return _file_size; - } - return filesystem::file_size(path()); -} -#endif - -GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept -{ - if (_file_size != static_cast(-1)) { - ec.clear(); - return _file_size; - } - return filesystem::file_size(path(), ec); -} - -#ifndef GHC_OS_WEB -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE uintmax_t directory_entry::hard_link_count() const -{ -#ifndef GHC_OS_WINDOWS - if (_hard_link_count != static_cast(-1)) { - return _hard_link_count; - } -#endif - return filesystem::hard_link_count(path()); -} -#endif - -GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept -{ -#ifndef GHC_OS_WINDOWS - if (_hard_link_count != static_cast(-1)) { - ec.clear(); - return _hard_link_count; - } -#endif - return filesystem::hard_link_count(path(), ec); -} -#endif - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE file_time_type directory_entry::last_write_time() const -{ - if (_last_write_time != 0) { - return std::chrono::system_clock::from_time_t(_last_write_time); - } - return filesystem::last_write_time(path()); -} -#endif - -GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept -{ - if (_last_write_time != 0) { - ec.clear(); - return std::chrono::system_clock::from_time_t(_last_write_time); - } - return filesystem::last_write_time(path(), ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE file_status directory_entry::status() const -{ - if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { - return _status; - } - return filesystem::status(path()); -} -#endif - -GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept -{ - if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { - ec.clear(); - return _status; - } - return filesystem::status(path(), ec); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE file_status directory_entry::symlink_status() const -{ - if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { - return _symlink_status; - } - return filesystem::symlink_status(path()); -} -#endif - -GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept -{ - if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { - ec.clear(); - return _symlink_status; - } - return filesystem::symlink_status(path(), ec); -} - -#ifdef GHC_HAS_THREEWAY_COMP -GHC_INLINE std::strong_ordering directory_entry::operator<=>(const directory_entry& rhs) const noexcept -{ - return _path <=> rhs._path; -} -#endif - -GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept -{ - return _path < rhs._path; -} - -GHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept -{ - return _path == rhs._path; -} - -GHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept -{ - return _path != rhs._path; -} - -GHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept -{ - return _path <= rhs._path; -} - -GHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept -{ - return _path > rhs._path; -} - -GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept -{ - return _path >= rhs._path; -} - -//----------------------------------------------------------------------------- -// [fs.class.directory_iterator] class directory_iterator - -#ifdef GHC_OS_WINDOWS -class directory_iterator::impl -{ -public: - impl(const path& p, directory_options options) - : _base(p) - , _options(options) - , _dirHandle(INVALID_HANDLE_VALUE) - { - if (!_base.empty()) { - ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW)); - if ((_dirHandle = FindFirstFileW(GHC_NATIVEWP((_base / "*")), &_findData)) != INVALID_HANDLE_VALUE) { - if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") { - increment(_ec); - } - else { - _dir_entry._path = _base / std::wstring(_findData.cFileName); - copyToDirEntry(_ec); - } - } - else { - auto error = ::GetLastError(); - _base = filesystem::path(); - if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) { - _ec = detail::make_system_error(); - } - } - } - } - impl(const impl& other) = delete; - ~impl() - { - if (_dirHandle != INVALID_HANDLE_VALUE) { - FindClose(_dirHandle); - _dirHandle = INVALID_HANDLE_VALUE; - } - } - void increment(std::error_code& ec) - { - if (_dirHandle != INVALID_HANDLE_VALUE) { - do { - if (FindNextFileW(_dirHandle, &_findData)) { - _dir_entry._path = _base; -#ifdef GHC_USE_WCHAR_T - _dir_entry._path.append_name(_findData.cFileName); -#else -#ifdef GHC_RAISE_UNICODE_ERRORS - try { - _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); - } - catch (filesystem_error& fe) { - ec = fe.code(); - return; - } -#else - _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); -#endif -#endif - copyToDirEntry(ec); - } - else { - auto err = ::GetLastError(); - if (err != ERROR_NO_MORE_FILES) { - _ec = ec = detail::make_system_error(err); - } - FindClose(_dirHandle); - _dirHandle = INVALID_HANDLE_VALUE; - _dir_entry._path.clear(); - break; - } - } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L".."); - } - else { - ec = _ec; - } - } - void copyToDirEntry(std::error_code& ec) - { - if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - _dir_entry._status = detail::status_ex(_dir_entry._path, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time); - } - else { - _dir_entry._status = detail::status_from_INFO(_dir_entry._path, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time); - _dir_entry._symlink_status = _dir_entry._status; - } - if (ec) { - if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) { - ec.clear(); - } - else { - _dir_entry._file_size = static_cast(-1); - _dir_entry._last_write_time = 0; - } - } - } - path _base; - directory_options _options; - WIN32_FIND_DATAW _findData; - HANDLE _dirHandle; - directory_entry _dir_entry; - std::error_code _ec; -}; -#else -// POSIX implementation -class directory_iterator::impl -{ -public: - impl(const path& path, directory_options options) - : _base(path) - , _options(options) - , _dir(nullptr) - , _entry(nullptr) - { - if (!path.empty()) { - _dir = ::opendir(path.native().c_str()); - if (!_dir) { - auto error = errno; - _base = filesystem::path(); - if ((error != EACCES && error != EPERM) || (options & directory_options::skip_permission_denied) == directory_options::none) { - _ec = detail::make_system_error(); - } - } - else { - increment(_ec); - } - } - } - impl(const impl& other) = delete; - ~impl() - { - if (_dir) { - ::closedir(_dir); - } - } - void increment(std::error_code& ec) - { - if (_dir) { - bool skip; - do { - skip = false; - errno = 0; - _entry = ::readdir(_dir); - if (_entry) { - _dir_entry._path = _base; - _dir_entry._path.append_name(_entry->d_name); - copyToDirEntry(); - if (ec && (ec.value() == EACCES || ec.value() == EPERM) && (_options & directory_options::skip_permission_denied) == directory_options::skip_permission_denied) { - ec.clear(); - skip = true; - } - } - else { - ::closedir(_dir); - _dir = nullptr; - _dir_entry._path.clear(); - if (errno) { - ec = detail::make_system_error(); - } - break; - } - } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); - } - } - - void copyToDirEntry() - { -#ifdef GHC_NO_DIRENT_D_TYPE - _dir_entry._symlink_status = file_status(); - _dir_entry._status = file_status(); -#else - _dir_entry._symlink_status.permissions(perms::unknown); - switch(_entry->d_type) { - case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break; - case DT_CHR: _dir_entry._symlink_status.type(file_type::character); break; - case DT_DIR: _dir_entry._symlink_status.type(file_type::directory); break; - case DT_FIFO: _dir_entry._symlink_status.type(file_type::fifo); break; - case DT_LNK: _dir_entry._symlink_status.type(file_type::symlink); break; - case DT_REG: _dir_entry._symlink_status.type(file_type::regular); break; - case DT_SOCK: _dir_entry._symlink_status.type(file_type::socket); break; - case DT_UNKNOWN: _dir_entry._symlink_status.type(file_type::none); break; - default: _dir_entry._symlink_status.type(file_type::unknown); break; - } - if (_entry->d_type != DT_LNK) { - _dir_entry._status = _dir_entry._symlink_status; - } - else { - _dir_entry._status.type(file_type::none); - _dir_entry._status.permissions(perms::unknown); - } -#endif - _dir_entry._file_size = static_cast(-1); - _dir_entry._hard_link_count = static_cast(-1); - _dir_entry._last_write_time = 0; - } - path _base; - directory_options _options; - DIR* _dir; - struct ::dirent* _entry; - directory_entry _dir_entry; - std::error_code _ec; -}; -#endif - -// [fs.dir.itr.members] member functions -GHC_INLINE directory_iterator::directory_iterator() noexcept - : _impl(new impl(path(), directory_options::none)) -{ -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE directory_iterator::directory_iterator(const path& p) - : _impl(new impl(p, directory_options::none)) -{ - if (_impl->_ec) { - throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); - } - _impl->_ec.clear(); -} - -GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options) - : _impl(new impl(p, options)) -{ - if (_impl->_ec) { - throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); - } -} -#endif - -GHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept - : _impl(new impl(p, directory_options::none)) -{ - if (_impl->_ec) { - ec = _impl->_ec; - } -} - -GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept - : _impl(new impl(p, options)) -{ - if (_impl->_ec) { - ec = _impl->_ec; - } -} - -GHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs) - : _impl(rhs._impl) -{ -} - -GHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept - : _impl(std::move(rhs._impl)) -{ -} - -GHC_INLINE directory_iterator::~directory_iterator() {} - -GHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs) -{ - _impl = rhs._impl; - return *this; -} - -GHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept -{ - _impl = std::move(rhs._impl); - return *this; -} - -GHC_INLINE const directory_entry& directory_iterator::operator*() const -{ - return _impl->_dir_entry; -} - -GHC_INLINE const directory_entry* directory_iterator::operator->() const -{ - return &_impl->_dir_entry; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE directory_iterator& directory_iterator::operator++() -{ - std::error_code ec; - _impl->increment(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec); - } - return *this; -} -#endif - -GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept -{ - _impl->increment(ec); - return *this; -} - -GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const -{ - return _impl->_dir_entry._path == rhs._impl->_dir_entry._path; -} - -GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const -{ - return _impl->_dir_entry._path != rhs._impl->_dir_entry._path; -} - -// [fs.dir.itr.nonmembers] directory_iterator non-member functions - -GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept -{ - return iter; -} - -GHC_INLINE directory_iterator end(const directory_iterator&) noexcept -{ - return directory_iterator(); -} - -//----------------------------------------------------------------------------- -// [fs.class.rec.dir.itr] class recursive_directory_iterator - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept - : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator()); -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p) - : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p)); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options) - : _impl(new recursive_directory_iterator_impl(options, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p, options)); -} -#endif - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept - : _impl(new recursive_directory_iterator_impl(options, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p, options, ec)); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept - : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p, ec)); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs) - : _impl(rhs._impl) -{ -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept - : _impl(std::move(rhs._impl)) -{ -} - -GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {} - -// [fs.rec.dir.itr.members] observers -GHC_INLINE directory_options recursive_directory_iterator::options() const -{ - return _impl->_options; -} - -GHC_INLINE int recursive_directory_iterator::depth() const -{ - return static_cast(_impl->_dir_iter_stack.size() - 1); -} - -GHC_INLINE bool recursive_directory_iterator::recursion_pending() const -{ - return _impl->_recursion_pending; -} - -GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const -{ - return *(_impl->_dir_iter_stack.top()); -} - -GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const -{ - return &(*(_impl->_dir_iter_stack.top())); -} - -// [fs.rec.dir.itr.members] modifiers recursive_directory_iterator& -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs) -{ - _impl = rhs._impl; - return *this; -} - -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept -{ - _impl = std::move(rhs._impl); - return *this; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++() -{ - std::error_code ec; - increment(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); - } - return *this; -} -#endif - -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept -{ - bool isSymLink = (*this)->is_symlink(ec); - bool isDir = !ec && (*this)->is_directory(ec); - if(isSymLink && detail::is_not_found_error(ec)) { - ec.clear(); - } - if(!ec) { - if (recursion_pending() && isDir && (!isSymLink || (options() & directory_options::follow_directory_symlink) != directory_options::none)) { - _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec)); - } - else { - _impl->_dir_iter_stack.top().increment(ec); - } - 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->_recursion_pending = true; - } - return *this; -} - -#ifdef GHC_WITH_EXCEPTIONS -GHC_INLINE void recursive_directory_iterator::pop() -{ - std::error_code ec; - pop(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); - } -} -#endif - -GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec) -{ - if (depth() == 0) { - *this = recursive_directory_iterator(); - } - else { - do { - _impl->_dir_iter_stack.pop(); - _impl->_dir_iter_stack.top().increment(ec); - } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()); - } -} - -GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() -{ - _impl->_recursion_pending = false; -} - -// other members as required by [input.iterators] -GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const -{ - return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top(); -} - -GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const -{ - return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top(); -} - -// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions -GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept -{ - return iter; -} - -GHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept -{ - return recursive_directory_iterator(); -} - -#endif // GHC_EXPAND_IMPL - -} // namespace filesystem -} // namespace ghc - -// cleanup some macros -#undef GHC_INLINE -#undef GHC_EXPAND_IMPL - -#endif // GHC_FILESYSTEM_H diff --git a/vendor/FileSystem/include/ghc/fs_fwd.hpp b/vendor/FileSystem/include/ghc/fs_fwd.hpp deleted file mode 100644 index 31188d16..00000000 --- a/vendor/FileSystem/include/ghc/fs_fwd.hpp +++ /dev/null @@ -1,38 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -// fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of -// ghc::filesystem. -// This file can be include at any place, where ghc::filesystem api is needed while -// not bleeding implementation details (e.g. system includes) into the global namespace, -// as long as one cpp includes fs_impl.hpp to deliver the matching implementations. -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_FWD_H -#define GHC_FILESYSTEM_FWD_H -#define GHC_FILESYSTEM_FWD -#include -#endif // GHC_FILESYSTEM_FWD_H diff --git a/vendor/FileSystem/include/ghc/fs_impl.hpp b/vendor/FileSystem/include/ghc/fs_impl.hpp deleted file mode 100644 index 92e3eaef..00000000 --- a/vendor/FileSystem/include/ghc/fs_impl.hpp +++ /dev/null @@ -1,35 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -// fs_impl.hpp - The implementation header for the header/implementation seperated usage of -// ghc::filesystem. -// This file can be used to hide the implementation of ghc::filesystem into a single cpp. -// The cpp has to include this before including fs_fwd.hpp directly or via a different -// header to work. -//--------------------------------------------------------------------------------------- -#define GHC_FILESYSTEM_IMPLEMENTATION -#include diff --git a/vendor/FileSystem/include/ghc/fs_std.hpp b/vendor/FileSystem/include/ghc/fs_std.hpp deleted file mode 100644 index c9492fdc..00000000 --- a/vendor/FileSystem/include/ghc/fs_std.hpp +++ /dev/null @@ -1,60 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -// 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 -// namespace fs. -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_STD_H -#define GHC_FILESYSTEM_STD_H -#if defined(__APPLE__) -#include -#endif -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -#if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -#define GHC_USE_STD_FS -#include -namespace fs { -using namespace std::filesystem; -using ifstream = std::ifstream; -using ofstream = std::ofstream; -using fstream = std::fstream; -} -#endif -#endif -#ifndef GHC_USE_STD_FS -//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE -#include -namespace fs { -using namespace ghc::filesystem; -using ifstream = ghc::filesystem::ifstream; -using ofstream = ghc::filesystem::ofstream; -using fstream = ghc::filesystem::fstream; -} -#endif -#endif // GHC_FILESYSTEM_STD_H - diff --git a/vendor/FileSystem/include/ghc/fs_std_fwd.hpp b/vendor/FileSystem/include/ghc/fs_std_fwd.hpp deleted file mode 100644 index 163c956a..00000000 --- a/vendor/FileSystem/include/ghc/fs_std_fwd.hpp +++ /dev/null @@ -1,63 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -// fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of -// ghc::filesystem that uses std::filesystem if it detects it. -// This file can be include at any place, where fs::filesystem api is needed while -// not bleeding implementation details (e.g. system includes) into the global namespace, -// as long as one cpp includes fs_std_impl.hpp to deliver the matching implementations. -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_STD_FWD_H -#define GHC_FILESYSTEM_STD_FWD_H -#if defined(__APPLE__) -#include -#endif -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -#if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -#define GHC_USE_STD_FS -#include -namespace fs { -using namespace std::filesystem; -using ifstream = std::ifstream; -using ofstream = std::ofstream; -using fstream = std::fstream; -} -#endif -#endif -#ifndef GHC_USE_STD_FS -//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE -#define GHC_FILESYSTEM_FWD -#include -namespace fs { -using namespace ghc::filesystem; -using ifstream = ghc::filesystem::ifstream; -using ofstream = ghc::filesystem::ofstream; -using fstream = ghc::filesystem::fstream; -} -#endif -#endif // GHC_FILESYSTEM_STD_FWD_H - diff --git a/vendor/FileSystem/include/ghc/fs_std_impl.hpp b/vendor/FileSystem/include/ghc/fs_std_impl.hpp deleted file mode 100644 index 7042edca..00000000 --- a/vendor/FileSystem/include/ghc/fs_std_impl.hpp +++ /dev/null @@ -1,46 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -// fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of -// ghc::filesystem that does nothing if std::filesystem is detected. -// This file can be used to hide the implementation of ghc::filesystem into a single cpp. -// The cpp has to include this before including fs_std_fwd.hpp directly or via a different -// header to work. -//--------------------------------------------------------------------------------------- -#if defined(__APPLE__) -#include -#endif -#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -#if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -#define GHC_USE_STD_FS -#endif -#endif -#ifndef GHC_USE_STD_FS -//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE -#define GHC_FILESYSTEM_IMPLEMENTATION -#include -#endif diff --git a/vendor/FileSystem/test/CMakeLists.txt b/vendor/FileSystem/test/CMakeLists.txt deleted file mode 100644 index f9fdd187..00000000 --- a/vendor/FileSystem/test/CMakeLists.txt +++ /dev/null @@ -1,91 +0,0 @@ - -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") -set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON) -include(ParseAndAddCatchTests) - -if(GHC_COVERAGE) - message("Generating test runner for coverage run...") - set(CMAKE_EXE_LINKER_FLAGS "${CMCMAKE_EXE_LINKER_FLAGS} --coverage") - add_executable(filesystem_test filesystem_test.cpp catch.hpp) - if(MINGW) - target_compile_options(filesystem_test PUBLIC --coverage "-Wa,-mbig-obj") - else() - target_compile_options(filesystem_test PUBLIC --coverage) - endif() - target_link_libraries(filesystem_test PUBLIC ghc_filesystem --coverage) - if("cxx_std_17" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES) - AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp) - endif() - if("cxx_std_20" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES) - AddTestExecutableWithStdCpp(20 filesystem_test.cpp catch.hpp) - endif() -else() - message("Generating test runner for normal test...") - add_executable(filesystem_test filesystem_test.cpp catch.hpp) - target_link_libraries(filesystem_test ghc_filesystem) - target_compile_options(filesystem_test PRIVATE - $<$:-s DISABLE_EXCEPTION_CATCHING=0> - $<$,$>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror> - $<$:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror> - $<$:/WX> - $<$:-Wa,-mbig-obj>) - if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) - target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX) - endif() - if(EMSCRIPTEN) - set_target_properties(filesystem_test PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1") - endif() - ParseAndAddCatchTests(filesystem_test) - if(GHC_FILESYSTEM_BUILD_STD_TESTING) - AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp) - endif() - if(WIN32) - add_executable(filesystem_test_char filesystem_test.cpp catch.hpp) - target_link_libraries(filesystem_test_char ghc_filesystem) - target_compile_options(filesystem_test_char PRIVATE - $<$:-Wall -Wextra -Werror> - $<$:-Wall -Werror> - $<$:/WX>) - if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) - target_compile_definitions(filesystem_test_char PRIVATE _CRT_SECURE_NO_WARNINGS GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE) - else() - target_compile_definitions(filesystem_test_char PRIVATE GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE) - endif() - ParseAndAddCatchTests(filesystem_test_char) - endif() - if("cxx_std_17" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES) - AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp) - endif() - if("cxx_std_20" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES) - AddTestExecutableWithStdCpp(20 filesystem_test.cpp catch.hpp) - endif() -endif() - -add_executable(multifile_test multi1.cpp multi2.cpp catch.hpp) -target_link_libraries(multifile_test ghc_filesystem) -add_test(multifile_test multifile_test) - -add_executable(fwd_impl_test fwd_test.cpp impl_test.cpp) -target_link_libraries(fwd_impl_test ghc_filesystem) -target_compile_options(fwd_impl_test PRIVATE - $<$:-s DISABLE_EXCEPTION_CATCHING=0> - $<$,$>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror> - $<$:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror> - $<$:/WX> - $<$:-Wa,-mbig-obj>) -if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) - target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX) -endif() -add_test(fwd_impl_test fwd_impl_test) - -add_executable(exception exception.cpp) -if(NOT MSVC) - target_compile_options(exception PRIVATE -fno-exceptions) -endif() -target_include_directories(exception PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include) -target_compile_options(exception PRIVATE - $<$:-s DISABLE_EXCEPTION_CATCHING=0> - $<$,$>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror> - $<$:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror> - $<$:/WX> - $<$:-Wa,-mbig-obj>) diff --git a/vendor/FileSystem/test/catch.hpp b/vendor/FileSystem/test/catch.hpp deleted file mode 100644 index b0fa6416..00000000 --- a/vendor/FileSystem/test/catch.hpp +++ /dev/null @@ -1,13922 +0,0 @@ -/* - * Catch v2.4.0 - * Generated: 2018-09-04 11:55:01.682061 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp - - -#define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 4 -#define CATCH_VERSION_PATCH 0 - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// start catch_suppress_warnings.h - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif -#elif defined __GNUC__ - // GCC likes to warn on REQUIREs, and we cannot suppress them - // locally because g++'s support for _Pragma is lacking in older, - // still supported, versions -# pragma GCC diagnostic ignored "-Wparentheses" -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" -#endif -// end catch_suppress_warnings.h -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS -#endif - -// In the impl file, we want to have access to all parts of the headers -// Can also be used to sanely support PCHs -#if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -# endif -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) -// start catch_platform.h - -#ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// start catch_user_interfaces.h - -namespace Catch { - unsigned int rngSeed(); -} - -// end catch_user_interfaces.h -// start catch_tag_alias_autoregistrar.h - -// start catch_common.h - -// start catch_compiler_capabilities.h - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -#ifdef __cplusplus - -# if __cplusplus >= 201402L -# define CATCH_CPP14_OR_GREATER -# endif - -# if __cplusplus >= 201703L -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -#if defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#ifdef __clang__ - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif - -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif - -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE - -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif - -//////////////////////////////////////////////////////////////////////////////// -// DJGPP -#ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -//////////////////////////////////////////////////////////////////////////////// - -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER -#endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif -// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. -#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS -#endif - -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif - -// end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#include -#include -#include - -namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; - - struct SourceLineInfo { - - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; - - bool empty() const noexcept; - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -// end catch_common.h -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h - -// start catch_interfaces_testcase.h - -#include -#include - -namespace Catch { - - class TestSpec; - - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; - - using ITestCasePtr = std::shared_ptr; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include - -namespace Catch { - - class StringData; - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. - class StringRef { - public: - using size_type = std::size_t; - - private: - friend struct StringRefTestAccess; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - - static constexpr char const* const s_empty = ""; - - public: // construction/ assignment - StringRef() noexcept - : StringRef( s_empty, 0 ) - {} - - StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } - - StringRef( char const* rawChars ) noexcept; - - StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - ~StringRef() noexcept { - delete[] m_data; - } - - auto operator = ( StringRef const &other ) noexcept -> StringRef& { - delete[] m_data; - m_data = nullptr; - m_start = other.m_start; - m_size = other.m_size; - return *this; - } - - operator std::string() const; - - void swap( StringRef& other ) noexcept; - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; - - auto operator[] ( size_type index ) const noexcept -> char; - - public: // named queries - auto empty() const noexcept -> bool { - return m_size == 0; - } - auto size() const noexcept -> size_type { - return m_size; - } - - auto numberOfCharacters() const noexcept -> size_type; - auto c_str() const -> char const*; - - public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; - - // Returns the current start pointer. - // Note that the pointer can change when if the StringRef is a substring - auto currentData() const noexcept -> char const*; - - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; - }; - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } - -} // namespace Catch - -inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -// end catch_stringref.h -namespace Catch { - -template -class TestInvokerAsMethod : public ITestInvoker { - void (C::*m_testAsMethod)(); -public: - TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} - - void invoke() const override { - C obj; - (obj.*m_testAsMethod)(); - } -}; - -auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; - -template -auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); -} - -struct NameAndTags { - NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; - StringRef name; - StringRef tags; -}; - -struct AutoReg : NonCopyable { - AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; - ~AutoReg(); -}; - -} // end namespace Catch - -#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) -#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ -#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ -#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF - -#if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ - namespace{ \ - struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ - void test(); \ - }; \ - } \ - void TestName::test() - -#endif - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ - static void TestName(); \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ \ - struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - void TestName::test() - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - -// end catch_test_registry.h -// start catch_capture.hpp - -// start catch_assertionhandler.h - -// start catch_assertioninfo.h - -// start catch_result_type.h - -namespace Catch { - - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, - - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); - - bool shouldContinueOnFailure( int flags ); - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - bool shouldSuppressFailure( int flags ); - -} // end namespace Catch - -// end catch_result_type.h -namespace Catch { - - struct AssertionInfo - { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - - // We want to delete this constructor but a compiler bug in 4.8 means - // the struct is then treated as non-aggregate - //AssertionInfo() = delete; - }; - -} // end namespace Catch - -// end catch_assertioninfo.h -// start catch_decomposer.h - -// start catch_tostring.h - -#include -#include -#include -#include -// start catch_stream.h - -#include -#include -#include - -namespace Catch { - - std::ostream& cout(); - std::ostream& cerr(); - std::ostream& clog(); - - class StringRef; - - struct IStream { - virtual ~IStream(); - virtual std::ostream& stream() const = 0; - }; - - auto makeStream( StringRef const &filename ) -> IStream const*; - - class ReusableStringStream { - std::size_t m_index; - std::ostream* m_oss; - public: - ReusableStringStream(); - ~ReusableStringStream(); - - auto str() const -> std::string; - - template - auto operator << ( T const& value ) -> ReusableStringStream& { - *m_oss << value; - return *this; - } - auto get() -> std::ostream& { return *m_oss; } - }; -} - -// end catch_stream.h - -#ifdef __OBJC__ -// start catch_objc_arc.hpp - -#import - -#ifdef __has_feature -#define CATCH_ARC_ENABLED __has_feature(objc_arc) -#else -#define CATCH_ARC_ENABLED 0 -#endif - -void arcSafeRelease( NSObject* obj ); -id performOptionalSelector( id obj, SEL sel ); - -#if !CATCH_ARC_ENABLED -inline void arcSafeRelease( NSObject* obj ) { - [obj release]; -} -inline id performOptionalSelector( id obj, SEL sel ) { - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; - return nil; -} -#define CATCH_UNSAFE_UNRETAINED -#define CATCH_ARC_STRONG -#else -inline void arcSafeRelease( NSObject* ){} -inline id performOptionalSelector( id obj, SEL sel ) { -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" -#endif - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - return nil; -} -#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained -#define CATCH_ARC_STRONG __strong -#endif - -// end catch_objc_arc.hpp -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless -#endif - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - // Bring in operator<< from global namespace into Catch namespace - using ::operator<<; - - namespace Detail { - - extern const std::string unprintableString; - - std::string rawMemoryToString( const void *object, std::size_t size ); - - template - std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } - - template - class IsStreamInsertable { - template - static auto test(int) - -> decltype(std::declval() << std::declval(), std::true_type()); - - template - static auto test(...)->std::false_type; - - public: - static const bool value = decltype(test(0))::value; - }; - - template - std::string convertUnknownEnumToString( E e ); - - template - typename std::enable_if< - !std::is_enum::value && !std::is_base_of::value, - std::string>::type convertUnstreamable( T const& ) { - return Detail::unprintableString; - } - template - typename std::enable_if< - !std::is_enum::value && std::is_base_of::value, - std::string>::type convertUnstreamable(T const& ex) { - return ex.what(); - } - - template - typename std::enable_if< - std::is_enum::value - , std::string>::type convertUnstreamable( T const& value ) { - return convertUnknownEnumToString( value ); - } - -#if defined(_MANAGED) - //! Convert a CLR string to a utf8 std::string - template - std::string clrReferenceToString( T^ ref ) { - if (ref == nullptr) - return std::string("null"); - auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); - cli::pin_ptr p = &bytes[0]; - return std::string(reinterpret_cast(p), bytes->Length); - } -#endif - - } // namespace Detail - - // If we decide for C++14, change these to enable_if_ts - template - struct StringMaker { - template - static - typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type - convert(const Fake& value) { - ReusableStringStream rss; - // NB: call using the function-like syntax to avoid ambiguity with - // user-defined templated operator<< under clang. - rss.operator<<(value); - return rss.str(); - } - - template - static - typename std::enable_if::value, std::string>::type - convert( const Fake& value ) { -#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) - return Detail::convertUnstreamable(value); -#else - return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); -#endif - } - }; - - namespace Detail { - - // This function dispatches all stringification requests inside of Catch. - // Should be preferably called fully qualified, like ::Catch::Detail::stringify - template - std::string stringify(const T& e) { - return ::Catch::StringMaker::type>::type>::convert(e); - } - - template - std::string convertUnknownEnumToString( E e ) { - return ::Catch::Detail::stringify(static_cast::type>(e)); - } - -#if defined(_MANAGED) - template - std::string stringify( T^ e ) { - return ::Catch::StringMaker::convert(e); - } -#endif - - } // namespace Detail - - // Some predefined specializations - - template<> - struct StringMaker { - static std::string convert(const std::string& str); - }; -#ifdef CATCH_CONFIG_WCHAR - template<> - struct StringMaker { - static std::string convert(const std::wstring& wstr); - }; -#endif - - template<> - struct StringMaker { - static std::string convert(char const * str); - }; - template<> - struct StringMaker { - static std::string convert(char * str); - }; - -#ifdef CATCH_CONFIG_WCHAR - template<> - struct StringMaker { - static std::string convert(wchar_t const * str); - }; - template<> - struct StringMaker { - static std::string convert(wchar_t * str); - }; -#endif - - // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, - // while keeping string semantics? - template - struct StringMaker { - static std::string convert(char const* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; - template - struct StringMaker { - static std::string convert(signed char const* str) { - return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); - } - }; - template - struct StringMaker { - static std::string convert(unsigned char const* str) { - return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); - } - }; - - template<> - struct StringMaker { - static std::string convert(int value); - }; - template<> - struct StringMaker { - static std::string convert(long value); - }; - template<> - struct StringMaker { - static std::string convert(long long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned int value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long long value); - }; - - template<> - struct StringMaker { - static std::string convert(bool b); - }; - - template<> - struct StringMaker { - static std::string convert(char c); - }; - template<> - struct StringMaker { - static std::string convert(signed char c); - }; - template<> - struct StringMaker { - static std::string convert(unsigned char c); - }; - - template<> - struct StringMaker { - static std::string convert(std::nullptr_t); - }; - - template<> - struct StringMaker { - static std::string convert(float value); - }; - template<> - struct StringMaker { - static std::string convert(double value); - }; - - template - struct StringMaker { - template - static std::string convert(U* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - - template - struct StringMaker { - static std::string convert(R C::* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - -#if defined(_MANAGED) - template - struct StringMaker { - static std::string convert( T^ ref ) { - return ::Catch::Detail::clrReferenceToString(ref); - } - }; -#endif - - namespace Detail { - template - std::string rangeToString(InputIterator first, InputIterator last) { - ReusableStringStream rss; - rss << "{ "; - if (first != last) { - rss << ::Catch::Detail::stringify(*first); - for (++first; first != last; ++first) - rss << ", " << ::Catch::Detail::stringify(*first); - } - rss << " }"; - return rss.str(); - } - } - -#ifdef __OBJC__ - template<> - struct StringMaker { - static std::string convert(NSString * nsstring) { - if (!nsstring) - return "nil"; - return std::string("@") + [nsstring UTF8String]; - } - }; - template<> - struct StringMaker { - static std::string convert(NSObject* nsObject) { - return ::Catch::Detail::stringify([nsObject description]); - } - - }; - namespace Detail { - inline std::string stringify( NSString* nsstring ) { - return StringMaker::convert( nsstring ); - } - - } // namespace Detail -#endif // __OBJC__ - -} // namespace Catch - -////////////////////////////////////////////////////// -// Separate std-lib types stringification, so it can be selectively enabled -// This means that we do not bring in - -#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) -# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER -# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -#endif - -// Separate std::pair specialization -#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) -#include -namespace Catch { - template - struct StringMaker > { - static std::string convert(const std::pair& pair) { - ReusableStringStream rss; - rss << "{ " - << ::Catch::Detail::stringify(pair.first) - << ", " - << ::Catch::Detail::stringify(pair.second) - << " }"; - return rss.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER - -// Separate std::tuple specialization -#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) -#include -namespace Catch { - namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct TupleElementPrinter { - static void print(const Tuple& tuple, std::ostream& os) { - os << (N ? ", " : " ") - << ::Catch::Detail::stringify(std::get(tuple)); - TupleElementPrinter::print(tuple, os); - } - }; - - template< - typename Tuple, - std::size_t N - > - struct TupleElementPrinter { - static void print(const Tuple&, std::ostream&) {} - }; - - } - - template - struct StringMaker> { - static std::string convert(const std::tuple& tuple) { - ReusableStringStream rss; - rss << '{'; - Detail::TupleElementPrinter>::print(tuple, rss.get()); - rss << " }"; - return rss.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER - -namespace Catch { - struct not_this_one {}; // Tag type for detecting which begin/ end are being selected - - // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace - using std::begin; - using std::end; - - not_this_one begin( ... ); - not_this_one end( ... ); - - template - struct is_range { - static const bool value = - !std::is_same())), not_this_one>::value && - !std::is_same())), not_this_one>::value; - }; - -#if defined(_MANAGED) // Managed types are never ranges - template - struct is_range { - static const bool value = false; - }; -#endif - - template - std::string rangeToString( Range const& range ) { - return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); - } - - // Handle vector specially - template - std::string rangeToString( std::vector const& v ) { - ReusableStringStream rss; - rss << "{ "; - bool first = true; - for( bool b : v ) { - if( first ) - first = false; - else - rss << ", "; - rss << ::Catch::Detail::stringify( b ); - } - rss << " }"; - return rss.str(); - } - - template - struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { - static std::string convert( R const& range ) { - return rangeToString( range ); - } - }; - - template - struct StringMaker { - static std::string convert(T const(&arr)[SZ]) { - return rangeToString(arr); - } - }; - -} // namespace Catch - -// Separate std::chrono::duration specialization -#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -#include -#include -#include - -namespace Catch { - -template -struct ratio_string { - static std::string symbol(); -}; - -template -std::string ratio_string::symbol() { - Catch::ReusableStringStream rss; - rss << '[' << Ratio::num << '/' - << Ratio::den << ']'; - return rss.str(); -} -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; - - //////////// - // std::chrono::duration specializations - template - struct StringMaker> { - static std::string convert(std::chrono::duration const& duration) { - ReusableStringStream rss; - rss << duration.count() << ' ' << ratio_string::symbol() << 's'; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " s"; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " m"; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " h"; - return rss.str(); - } - }; - - //////////// - // std::chrono::time_point specialization - // Generic time_point cannot be specialized, only std::chrono::time_point - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; - } - }; - // std::chrono::time_point specialization - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - auto converted = std::chrono::system_clock::to_time_t(time_point); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &converted); -#else - std::tm* timeInfo = std::gmtime(&converted); -#endif - - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// end catch_tostring.h -#include - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#pragma warning(disable:4018) // more "signed/unsigned mismatch" -#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) -#pragma warning(disable:4180) // qualifier applied to function type has no meaning -#endif - -namespace Catch { - - struct ITransientExpression { - auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } - auto getResult() const -> bool { return m_result; } - virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - - ITransientExpression( bool isBinaryExpression, bool result ) - : m_isBinaryExpression( isBinaryExpression ), - m_result( result ) - {} - - // We don't actually need a virtual destructor, but many static analysers - // complain if it's not here :-( - virtual ~ITransientExpression(); - - bool m_isBinaryExpression; - bool m_result; - - }; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); - - template - class BinaryExpr : public ITransientExpression { - LhsT m_lhs; - StringRef m_op; - RhsT m_rhs; - - void streamReconstructedExpression( std::ostream &os ) const override { - formatReconstructedExpression - ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); - } - - public: - BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : ITransientExpression{ true, comparisonResult }, - m_lhs( lhs ), - m_op( op ), - m_rhs( rhs ) - {} - }; - - template - class UnaryExpr : public ITransientExpression { - LhsT m_lhs; - - void streamReconstructedExpression( std::ostream &os ) const override { - os << Catch::Detail::stringify( m_lhs ); - } - - public: - explicit UnaryExpr( LhsT lhs ) - : ITransientExpression{ false, lhs ? true : false }, - m_lhs( lhs ) - {} - }; - - // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) - template - auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } - template - auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - template - auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - - template - auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } - template - auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - template - auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - - template - class ExprLhs { - LhsT m_lhs; - public: - explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} - - template - auto operator == ( RhsT const& rhs ) -> BinaryExpr const { - return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; - } - auto operator == ( bool rhs ) -> BinaryExpr const { - return { m_lhs == rhs, m_lhs, "==", rhs }; - } - - template - auto operator != ( RhsT const& rhs ) -> BinaryExpr const { - return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; - } - auto operator != ( bool rhs ) -> BinaryExpr const { - return { m_lhs != rhs, m_lhs, "!=", rhs }; - } - - template - auto operator > ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; - } - template - auto operator < ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; - } - template - auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; - } - template - auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; - } - - auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr{ m_lhs }; - } - }; - - void handleExpression( ITransientExpression const& expr ); - - template - void handleExpression( ExprLhs const& expr ) { - handleExpression( expr.makeUnaryExpr() ); - } - - struct Decomposer { - template - auto operator <= ( T const& lhs ) -> ExprLhs { - return ExprLhs{ lhs }; - } - - auto operator <=( bool value ) -> ExprLhs { - return ExprLhs{ value }; - } - }; - -} // end namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// end catch_decomposer.h -// start catch_interfaces_capture.h - -#include - -namespace Catch { - - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct SectionEndInfo; - struct MessageInfo; - struct Counts; - struct BenchmarkInfo; - struct BenchmarkStats; - struct AssertionReaction; - struct SourceLineInfo; - - struct ITransientExpression; - struct IGeneratorTracker; - - struct IResultCapture { - - virtual ~IResultCapture(); - - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - - virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; - - virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual void handleFatalErrorCondition( StringRef message ) = 0; - - virtual void handleExpr - ( AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction ) = 0; - virtual void handleMessage - ( AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef const& message, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedExceptionNotThrown - ( AssertionInfo const& info, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedInflightException - ( AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction ) = 0; - virtual void handleIncomplete - ( AssertionInfo const& info ) = 0; - virtual void handleNonExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction ) = 0; - - virtual bool lastAssertionPassed() = 0; - virtual void assertionPassed() = 0; - - // Deprecated, do not use: - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; - virtual void exceptionEarlyReported() = 0; - }; - - IResultCapture& getResultCapture(); -} - -// end catch_interfaces_capture.h -namespace Catch { - - struct TestFailureException{}; - struct AssertionResultData; - struct IResultCapture; - class RunContext; - - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; - friend class RunContext; - - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ); - LazyExpression( LazyExpression const& other ); - LazyExpression& operator = ( LazyExpression const& ) = delete; - - explicit operator bool() const; - - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; - }; - - struct AssertionReaction { - bool shouldDebugBreak = false; - bool shouldThrow = false; - }; - - class AssertionHandler { - AssertionInfo m_assertionInfo; - AssertionReaction m_reaction; - bool m_completed = false; - IResultCapture& m_resultCapture; - - public: - AssertionHandler - ( StringRef const& macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ); - ~AssertionHandler() { - if ( !m_completed ) { - m_resultCapture.handleIncomplete( m_assertionInfo ); - } - } - - template - void handleExpr( ExprLhs const& expr ) { - handleExpr( expr.makeUnaryExpr() ); - } - void handleExpr( ITransientExpression const& expr ); - - void handleMessage(ResultWas::OfType resultType, StringRef const& message); - - void handleExceptionThrownAsExpected(); - void handleUnexpectedExceptionNotThrown(); - void handleExceptionNotThrownAsExpected(); - void handleThrowingCallSkipped(); - void handleUnexpectedInflightException(); - - void complete(); - void setCompleted(); - - // query - auto allowThrows() const -> bool; - }; - - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); - -} // namespace Catch - -// end catch_assertionhandler.h -// start catch_message.h - -#include -#include - -namespace Catch { - - struct MessageInfo { - MessageInfo( StringRef const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); - - StringRef macroName; - std::string message; - SourceLineInfo lineInfo; - ResultWas::OfType type; - unsigned int sequence; - - bool operator == ( MessageInfo const& other ) const; - bool operator < ( MessageInfo const& other ) const; - private: - static unsigned int globalCount; - }; - - struct MessageStream { - - template - MessageStream& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - ReusableStringStream m_stream; - }; - - struct MessageBuilder : MessageStream { - MessageBuilder( StringRef const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ); - - template - MessageBuilder& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - MessageInfo m_info; - }; - - class ScopedMessage { - public: - explicit ScopedMessage( MessageBuilder const& builder ); - ~ScopedMessage(); - - MessageInfo m_info; - }; - - class Capturer { - std::vector m_messages; - IResultCapture& m_resultCapture = getResultCapture(); - size_t m_captured = 0; - public: - Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); - ~Capturer(); - - void captureValue( size_t index, StringRef value ); - - template - void captureValues( size_t index, T&& value ) { - captureValue( index, Catch::Detail::stringify( value ) ); - } - - template - void captureValues( size_t index, T&& value, Ts&&... values ) { - captureValues( index, value ); - captureValues( index+1, values... ); - } - }; - -} // end namespace Catch - -// end catch_message.h -#if !defined(CATCH_CONFIG_DISABLE) - -#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ -#else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" -#endif - -#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - -/////////////////////////////////////////////////////////////////////////////// -// Another way to speed-up compilation is to omit local try-catch for REQUIRE* -// macros. -#define INTERNAL_CATCH_TRY -#define INTERNAL_CATCH_CATCH( capturer ) - -#else // CATCH_CONFIG_FAST_COMPILE - -#define INTERNAL_CATCH_TRY try -#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } - -#endif - -#define INTERNAL_CATCH_REACT( handler ) handler.complete(); - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY { \ - CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ - CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look - // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( Catch::getResultCapture().lastAssertionPassed() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( !Catch::getResultCapture().lastAssertionPassed() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleExceptionThrownAsExpected(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(expr); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( exceptionType const& ) { \ - catchAssertionHandler.handleExceptionThrownAsExpected(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ - catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ - auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ - varName.captureValues( 0, __VA_ARGS__ ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_INFO( macroName, log ) \ - Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); - -/////////////////////////////////////////////////////////////////////////////// -// Although this is matcher-based, it can be used with just a string -#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( ... ) { \ - Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -#endif // CATCH_CONFIG_DISABLE - -// end catch_capture.hpp -// start catch_section.h - -// start catch_section_info.h - -// start catch_totals.h - -#include - -namespace Catch { - - struct Counts { - Counts operator - ( Counts const& other ) const; - Counts& operator += ( Counts const& other ); - - std::size_t total() const; - bool allPassed() const; - bool allOk() const; - - std::size_t passed = 0; - std::size_t failed = 0; - std::size_t failedButOk = 0; - }; - - struct Totals { - - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); - - Totals delta( Totals const& prevTotals ) const; - - int error = 0; - Counts assertions; - Counts testCases; - }; -} - -// end catch_totals.h -#include - -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name ); - - // Deprecated - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& ) : SectionInfo( _lineInfo, _name ) {} - - std::string name; - std::string description; // !Deprecated: this will always be empty - SourceLineInfo lineInfo; - }; - - struct SectionEndInfo { - SectionInfo sectionInfo; - Counts prevAssertions; - double durationInSeconds; - }; - -} // end namespace Catch - -// end catch_section_info.h -// start catch_timer.h - -#include - -namespace Catch { - - auto getCurrentNanosecondsSinceEpoch() -> uint64_t; - auto getEstimatedClockResolution() -> uint64_t; - - class Timer { - uint64_t m_nanoseconds = 0; - public: - void start(); - auto getElapsedNanoseconds() const -> uint64_t; - auto getElapsedMicroseconds() const -> uint64_t; - auto getElapsedMilliseconds() const -> unsigned int; - auto getElapsedSeconds() const -> double; - }; - -} // namespace Catch - -// end catch_timer.h -#include - -namespace Catch { - - class Section : NonCopyable { - public: - Section( SectionInfo const& info ); - ~Section(); - - // This indicates whether the section should be executed or not - explicit operator bool() const; - - private: - SectionInfo m_info; - - std::string m_name; - Counts m_assertions; - bool m_sectionIncluded; - Timer m_timer; - }; - -} // end namespace Catch - -#define INTERNAL_CATCH_SECTION( ... ) \ - CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ - CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS - -#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ - CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ - CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS - -// end catch_section.h -// start catch_benchmark.h - -#include -#include - -namespace Catch { - - class BenchmarkLooper { - - std::string m_name; - std::size_t m_count = 0; - std::size_t m_iterationsToRun = 1; - uint64_t m_resolution; - Timer m_timer; - - static auto getResolution() -> uint64_t; - public: - // Keep most of this inline as it's on the code path that is being timed - BenchmarkLooper( StringRef name ) - : m_name( name ), - m_resolution( getResolution() ) - { - reportStart(); - m_timer.start(); - } - - explicit operator bool() { - if( m_count < m_iterationsToRun ) - return true; - return needsMoreIterations(); - } - - void increment() { - ++m_count; - } - - void reportStart(); - auto needsMoreIterations() -> bool; - }; - -} // end namespace Catch - -#define BENCHMARK( name ) \ - for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) - -// end catch_benchmark.h -// start catch_interfaces_exception.h - -// start catch_interfaces_registry_hub.h - -#include -#include - -namespace Catch { - - class TestCase; - struct ITestCaseRegistry; - struct IExceptionTranslatorRegistry; - struct IExceptionTranslator; - struct IReporterRegistry; - struct IReporterFactory; - struct ITagAliasRegistry; - class StartupExceptionRegistry; - - using IReporterFactoryPtr = std::shared_ptr; - - struct IRegistryHub { - virtual ~IRegistryHub(); - - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - - virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; - - virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; - }; - - struct IMutableRegistryHub { - virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; - virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; - virtual void registerTest( TestCase const& testInfo ) = 0; - virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; - virtual void registerStartupException() noexcept = 0; - }; - - IRegistryHub const& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); - -} - -// end catch_interfaces_registry_hub.h -#if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ - static std::string translatorName( signature ) -#endif - -#include -#include -#include - -namespace Catch { - using exceptionTranslateFunction = std::string(*)(); - - struct IExceptionTranslator; - using ExceptionTranslators = std::vector>; - - struct IExceptionTranslator { - virtual ~IExceptionTranslator(); - virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; - }; - - struct IExceptionTranslatorRegistry { - virtual ~IExceptionTranslatorRegistry(); - - virtual std::string translateActiveException() const = 0; - }; - - class ExceptionTranslatorRegistrar { - template - class ExceptionTranslator : public IExceptionTranslator { - public: - - ExceptionTranslator( std::string(*translateFunction)( T& ) ) - : m_translateFunction( translateFunction ) - {} - - std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { - try { - if( it == itEnd ) - std::rethrow_exception(std::current_exception()); - else - return (*it)->translate( it+1, itEnd ); - } - catch( T& ex ) { - return m_translateFunction( ex ); - } - } - - protected: - std::string(*m_translateFunction)( T& ); - }; - - public: - template - ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { - getMutableRegistryHub().registerTranslator - ( new ExceptionTranslator( translateFunction ) ); - } - }; -} - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ - static std::string translatorName( signature ); \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - static std::string translatorName( signature ) - -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) - -// end catch_interfaces_exception.h -// start catch_approx.h - -#include - -namespace Catch { -namespace Detail { - - class Approx { - private: - bool equalityComparisonImpl(double other) const; - // Validates the new margin (margin >= 0) - // out-of-line to avoid including stdexcept in the header - void setMargin(double margin); - // Validates the new epsilon (0 < epsilon < 1) - // out-of-line to avoid including stdexcept in the header - void setEpsilon(double epsilon); - - public: - explicit Approx ( double value ); - - static Approx custom(); - - Approx operator-() const; - - template ::value>::type> - Approx operator()( T const& value ) { - Approx approx( static_cast(value) ); - approx.m_epsilon = m_epsilon; - approx.m_margin = m_margin; - approx.m_scale = m_scale; - return approx; - } - - template ::value>::type> - explicit Approx( T const& value ): Approx(static_cast(value)) - {} - - template ::value>::type> - friend bool operator == ( const T& lhs, Approx const& rhs ) { - auto lhs_v = static_cast(lhs); - return rhs.equalityComparisonImpl(lhs_v); - } - - template ::value>::type> - friend bool operator == ( Approx const& lhs, const T& rhs ) { - return operator==( rhs, lhs ); - } - - template ::value>::type> - friend bool operator != ( T const& lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - template ::value>::type> - friend bool operator != ( Approx const& lhs, T const& rhs ) { - return !operator==( rhs, lhs ); - } - - template ::value>::type> - friend bool operator <= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) < rhs.m_value || lhs == rhs; - } - - template ::value>::type> - friend bool operator <= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value < static_cast(rhs) || lhs == rhs; - } - - template ::value>::type> - friend bool operator >= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) > rhs.m_value || lhs == rhs; - } - - template ::value>::type> - friend bool operator >= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value > static_cast(rhs) || lhs == rhs; - } - - template ::value>::type> - Approx& epsilon( T const& newEpsilon ) { - double epsilonAsDouble = static_cast(newEpsilon); - setEpsilon(epsilonAsDouble); - return *this; - } - - template ::value>::type> - Approx& margin( T const& newMargin ) { - double marginAsDouble = static_cast(newMargin); - setMargin(marginAsDouble); - return *this; - } - - template ::value>::type> - Approx& scale( T const& newScale ) { - m_scale = static_cast(newScale); - return *this; - } - - std::string toString() const; - - private: - double m_epsilon; - double m_margin; - double m_scale; - double m_value; - }; -} // end namespace Detail - -namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); -} // end namespace literals - -template<> -struct StringMaker { - static std::string convert(Catch::Detail::Approx const& value); -}; - -} // end namespace Catch - -// end catch_approx.h -// start catch_string_manip.h - -#include -#include - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; -} - -// end catch_string_manip.h -#ifndef CATCH_CONFIG_DISABLE_MATCHERS -// start catch_capture_matchers.h - -// start catch_matchers.h - -#include -#include - -namespace Catch { -namespace Matchers { - namespace Impl { - - template struct MatchAllOf; - template struct MatchAnyOf; - template struct MatchNotOf; - - class MatcherUntypedBase { - public: - MatcherUntypedBase() = default; - MatcherUntypedBase ( MatcherUntypedBase const& ) = default; - MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; - std::string toString() const; - - protected: - virtual ~MatcherUntypedBase(); - virtual std::string describe() const = 0; - mutable std::string m_cachedToString; - }; - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wnon-virtual-dtor" -#endif - - template - struct MatcherMethod { - virtual bool match( ObjectT const& arg ) const = 0; - }; - template - struct MatcherMethod { - virtual bool match( PtrT* arg ) const = 0; - }; - -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { - - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; - }; - - template - struct MatchAllOf : MatcherBase { - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (!matcher->match(arg)) - return false; - } - return true; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " and "; - description += matcher->toString(); - } - description += " )"; - return description; - } - - MatchAllOf& operator && ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - template - struct MatchAnyOf : MatcherBase { - - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (matcher->match(arg)) - return true; - } - return false; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " or "; - description += matcher->toString(); - } - description += " )"; - return description; - } - - MatchAnyOf& operator || ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - - template - struct MatchNotOf : MatcherBase { - - MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - - bool match( ArgT const& arg ) const override { - return !m_underlyingMatcher.match( arg ); - } - - std::string describe() const override { - return "not " + m_underlyingMatcher.toString(); - } - MatcherBase const& m_underlyingMatcher; - }; - - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; - } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; - } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); - } - - } // namespace Impl - -} // namespace Matchers - -using namespace Matchers; -using Matchers::Impl::MatcherBase; - -} // namespace Catch - -// end catch_matchers.h -// start catch_matchers_floating.h - -#include -#include - -namespace Catch { -namespace Matchers { - - namespace Floating { - - enum class FloatingPointKind : uint8_t; - - struct WithinAbsMatcher : MatcherBase { - WithinAbsMatcher(double target, double margin); - bool match(double const& matchee) const override; - std::string describe() const override; - private: - double m_target; - double m_margin; - }; - - struct WithinUlpsMatcher : MatcherBase { - WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); - bool match(double const& matchee) const override; - std::string describe() const override; - private: - double m_target; - int m_ulps; - FloatingPointKind m_type; - }; - - } // namespace Floating - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); - Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); - Floating::WithinAbsMatcher WithinAbs(double target, double margin); - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_floating.h -// start catch_matchers_generic.hpp - -#include -#include - -namespace Catch { -namespace Matchers { -namespace Generic { - -namespace Detail { - std::string finalizeDescription(const std::string& desc); -} - -template -class PredicateMatcher : public MatcherBase { - std::function m_predicate; - std::string m_description; -public: - - PredicateMatcher(std::function const& elem, std::string const& descr) - :m_predicate(std::move(elem)), - m_description(Detail::finalizeDescription(descr)) - {} - - bool match( T const& item ) const override { - return m_predicate(item); - } - - std::string describe() const override { - return m_description; - } -}; - -} // namespace Generic - - // The following functions create the actual matcher objects. - // The user has to explicitly specify type to the function, because - // infering std::function is hard (but possible) and - // requires a lot of TMP. - template - Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { - return Generic::PredicateMatcher(predicate, description); - } - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_generic.hpp -// start catch_matchers_string.h - -#include - -namespace Catch { -namespace Matchers { - - namespace StdString { - - struct CasedString - { - CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); - std::string adjustString( std::string const& str ) const; - std::string caseSensitivitySuffix() const; - - CaseSensitive::Choice m_caseSensitivity; - std::string m_str; - }; - - struct StringMatcherBase : MatcherBase { - StringMatcherBase( std::string const& operation, CasedString const& comparator ); - std::string describe() const override; - - CasedString m_comparator; - std::string m_operation; - }; - - struct EqualsMatcher : StringMatcherBase { - EqualsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct ContainsMatcher : StringMatcherBase { - ContainsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct StartsWithMatcher : StringMatcherBase { - StartsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct EndsWithMatcher : StringMatcherBase { - EndsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - - struct RegexMatcher : MatcherBase { - RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); - bool match( std::string const& matchee ) const override; - std::string describe() const override; - - private: - std::string m_regex; - CaseSensitive::Choice m_caseSensitivity; - }; - - } // namespace StdString - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_string.h -// start catch_matchers_vector.h - -#include - -namespace Catch { -namespace Matchers { - - namespace Vector { - namespace Detail { - template - size_t count(InputIterator first, InputIterator last, T const& item) { - size_t cnt = 0; - for (; first != last; ++first) { - if (*first == item) { - ++cnt; - } - } - return cnt; - } - template - bool contains(InputIterator first, InputIterator last, T const& item) { - for (; first != last; ++first) { - if (*first == item) { - return true; - } - } - return false; - } - } - - template - struct ContainsElementMatcher : MatcherBase> { - - ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - - bool match(std::vector const &v) const override { - for (auto const& el : v) { - if (el == m_comparator) { - return true; - } - } - return false; - } - - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } - - T const& m_comparator; - }; - - template - struct ContainsMatcher : MatcherBase> { - - ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - - bool match(std::vector const &v) const override { - // !TBD: see note in EqualsMatcher - if (m_comparator.size() > v.size()) - return false; - for (auto const& comparator : m_comparator) { - auto present = false; - for (const auto& el : v) { - if (el == comparator) { - present = true; - break; - } - } - if (!present) { - return false; - } - } - return true; - } - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } - - std::vector const& m_comparator; - }; - - template - struct EqualsMatcher : MatcherBase> { - - EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - - bool match(std::vector const &v) const override { - // !TBD: This currently works if all elements can be compared using != - // - a more general approach would be via a compare template that defaults - // to using !=. but could be specialised for, e.g. std::vector etc - // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; - return true; - } - std::string describe() const override { - return "Equals: " + ::Catch::Detail::stringify( m_comparator ); - } - std::vector const& m_comparator; - }; - - template - struct UnorderedEqualsMatcher : MatcherBase> { - UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} - bool match(std::vector const& vec) const override { - // Note: This is a reimplementation of std::is_permutation, - // because I don't want to include inside the common path - if (m_target.size() != vec.size()) { - return false; - } - auto lfirst = m_target.begin(), llast = m_target.end(); - auto rfirst = vec.begin(), rlast = vec.end(); - // Cut common prefix to optimize checking of permuted parts - while (lfirst != llast && *lfirst != *rfirst) { - ++lfirst; ++rfirst; - } - if (lfirst == llast) { - return true; - } - - for (auto mid = lfirst; mid != llast; ++mid) { - // Skip already counted items - if (Detail::contains(lfirst, mid, *mid)) { - continue; - } - size_t num_vec = Detail::count(rfirst, rlast, *mid); - if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { - return false; - } - } - - return true; - } - - std::string describe() const override { - return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); - } - private: - std::vector const& m_target; - }; - - } // namespace Vector - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - - template - Vector::ContainsMatcher Contains( std::vector const& comparator ) { - return Vector::ContainsMatcher( comparator ); - } - - template - Vector::ContainsElementMatcher VectorContains( T const& comparator ) { - return Vector::ContainsElementMatcher( comparator ); - } - - template - Vector::EqualsMatcher Equals( std::vector const& comparator ) { - return Vector::EqualsMatcher( comparator ); - } - - template - Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { - return Vector::UnorderedEqualsMatcher(target); - } - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_vector.h -namespace Catch { - - template - class MatchExpr : public ITransientExpression { - ArgT const& m_arg; - MatcherT m_matcher; - StringRef m_matcherString; - public: - MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) - : ITransientExpression{ true, matcher.match( arg ) }, - m_arg( arg ), - m_matcher( matcher ), - m_matcherString( matcherString ) - {} - - void streamReconstructedExpression( std::ostream &os ) const override { - auto matcherAsString = m_matcher.toString(); - os << Catch::Detail::stringify( m_arg ) << ' '; - if( matcherAsString == Detail::unprintableString ) - os << m_matcherString; - else - os << matcherAsString; - } - }; - - using StringMatcher = Matchers::Impl::MatcherBase; - - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); - - template - auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr { - return MatchExpr( arg, matcher, matcherString ); - } - -} // namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - INTERNAL_CATCH_TRY { \ - catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( exceptionType const& ex ) { \ - catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -// end catch_capture_matchers.h -#endif -// start catch_generators.hpp - -// start catch_interfaces_generatortracker.h - - -#include - -namespace Catch { - - namespace Generators { - class GeneratorBase { - protected: - size_t m_size = 0; - - public: - GeneratorBase( size_t size ) : m_size( size ) {} - virtual ~GeneratorBase(); - auto size() const -> size_t { return m_size; } - }; - using GeneratorBasePtr = std::unique_ptr; - - } // namespace Generators - - struct IGeneratorTracker { - virtual ~IGeneratorTracker(); - virtual auto hasGenerator() const -> bool = 0; - virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; - virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; - virtual auto getIndex() const -> std::size_t = 0; - }; - -} // namespace Catch - -// end catch_interfaces_generatortracker.h -// start catch_enforce.h - -#include - -namespace Catch { -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - template - [[noreturn]] - void throw_exception(Ex const& e) { - throw e; - } -#else // ^^ Exceptions are enabled // Exceptions are disabled vv - [[noreturn]] - void throw_exception(std::exception const& e); -#endif -} // namespace Catch; - -#define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( ( Catch::ReusableStringStream() << msg ).str() ) -#define CATCH_INTERNAL_ERROR( msg ) \ - Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg)) -#define CATCH_ERROR( msg ) \ - Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg )) -#define CATCH_RUNTIME_ERROR( msg ) \ - Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg )) -#define CATCH_ENFORCE( condition, msg ) \ - do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) - -// end catch_enforce.h -#include -#include -#include - -#include - -namespace Catch { -namespace Generators { - - // !TBD move this into its own location? - namespace pf{ - template - std::unique_ptr make_unique( Args&&... args ) { - return std::unique_ptr(new T(std::forward(args)...)); - } - } - - template - struct IGenerator { - virtual ~IGenerator() {} - virtual auto get( size_t index ) const -> T = 0; - }; - - template - class SingleValueGenerator : public IGenerator { - T m_value; - public: - SingleValueGenerator( T const& value ) : m_value( value ) {} - - auto get( size_t ) const -> T override { - return m_value; - } - }; - - template - class FixedValuesGenerator : public IGenerator { - std::vector m_values; - - public: - FixedValuesGenerator( std::initializer_list values ) : m_values( values ) {} - - auto get( size_t index ) const -> T override { - return m_values[index]; - } - }; - - template - class RangeGenerator : public IGenerator { - T const m_first; - T const m_last; - - public: - RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) { - assert( m_last > m_first ); - } - - auto get( size_t index ) const -> T override { - // ToDo:: introduce a safe cast to catch potential overflows - return static_cast(m_first+index); - } - }; - - template - struct NullGenerator : IGenerator { - auto get( size_t ) const -> T override { - CATCH_INTERNAL_ERROR("A Null Generator is always empty"); - } - }; - - template - class Generator { - std::unique_ptr> m_generator; - size_t m_size; - - public: - Generator( size_t size, std::unique_ptr> generator ) - : m_generator( std::move( generator ) ), - m_size( size ) - {} - - auto size() const -> size_t { return m_size; } - auto operator[]( size_t index ) const -> T { - assert( index < m_size ); - return m_generator->get( index ); - } - }; - - std::vector randomiseIndices( size_t selectionSize, size_t sourceSize ); - - template - class GeneratorRandomiser : public IGenerator { - Generator m_baseGenerator; - - std::vector m_indices; - public: - GeneratorRandomiser( Generator&& baseGenerator, size_t numberOfItems ) - : m_baseGenerator( std::move( baseGenerator ) ), - m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) ) - {} - - auto get( size_t index ) const -> T override { - return m_baseGenerator[m_indices[index]]; - } - }; - - template - struct RequiresASpecialisationFor; - - template - auto all() -> Generator { return RequiresASpecialisationFor(); } - - template<> - auto all() -> Generator; - - template - auto range( T const& first, T const& last ) -> Generator { - return Generator( (last-first), pf::make_unique>( first, last ) ); - } - - template - auto random( T const& first, T const& last ) -> Generator { - auto gen = range( first, last ); - auto size = gen.size(); - - return Generator( size, pf::make_unique>( std::move( gen ), size ) ); - } - template - auto random( size_t size ) -> Generator { - return Generator( size, pf::make_unique>( all(), size ) ); - } - - template - auto values( std::initializer_list values ) -> Generator { - return Generator( values.size(), pf::make_unique>( values ) ); - } - template - auto value( T const& val ) -> Generator { - return Generator( 1, pf::make_unique>( val ) ); - } - - template - auto as() -> Generator { - return Generator( 0, pf::make_unique>() ); - } - - template - auto table( std::initializer_list>&& tuples ) -> Generator> { - return values>( std::forward>>( tuples ) ); - } - - template - struct Generators : GeneratorBase { - std::vector> m_generators; - - using type = T; - - Generators() : GeneratorBase( 0 ) {} - - void populate( T&& val ) { - m_size += 1; - m_generators.emplace_back( value( std::move( val ) ) ); - } - template - void populate( U&& val ) { - populate( T( std::move( val ) ) ); - } - void populate( Generator&& generator ) { - m_size += generator.size(); - m_generators.emplace_back( std::move( generator ) ); - } - - template - void populate( U&& valueOrGenerator, Gs... moreGenerators ) { - populate( std::forward( valueOrGenerator ) ); - populate( std::forward( moreGenerators )... ); - } - - auto operator[]( size_t index ) const -> T { - size_t sizes = 0; - for( auto const& gen : m_generators ) { - auto localIndex = index-sizes; - sizes += gen.size(); - if( index < sizes ) - return gen[localIndex]; - } - CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')'); - } - }; - - template - auto makeGenerators( Generator&& generator, Gs... moreGenerators ) -> Generators { - Generators generators; - generators.m_generators.reserve( 1+sizeof...(Gs) ); - generators.populate( std::move( generator ), std::forward( moreGenerators )... ); - return generators; - } - template - auto makeGenerators( Generator&& generator ) -> Generators { - Generators generators; - generators.populate( std::move( generator ) ); - return generators; - } - template - auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators { - return makeGenerators( value( std::forward( val ) ), std::forward( moreGenerators )... ); - } - template - auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators { - return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); - } - - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; - - template - // Note: The type after -> is weird, because VS2015 cannot parse - // the expression used in the typedef inside, when it is in - // return type. Yeah, ¯\_(ツ)_/¯ - auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval()[0]) { - using UnderlyingType = typename decltype(generatorExpression())::type; - - IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); - if( !tracker.hasGenerator() ) - tracker.setGenerator( pf::make_unique>( generatorExpression() ) ); - - auto const& generator = static_cast const&>( *tracker.getGenerator() ); - return generator[tracker.getIndex()]; - } - -} // namespace Generators -} // namespace Catch - -#define GENERATE( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) - -// end catch_generators.hpp - -// These files are included here so the single_include script doesn't put them -// in the conditionally compiled sections -// start catch_test_case_info.h - -#include -#include -#include - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - struct ITestInvoker; - - struct TestCaseInfo { - enum SpecialProperties{ - None = 0, - IsHidden = 1 << 1, - ShouldFail = 1 << 2, - MayFail = 1 << 3, - Throws = 1 << 4, - NonPortable = 1 << 5, - Benchmark = 1 << 6 - }; - - TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::vector const& _tags, - SourceLineInfo const& _lineInfo ); - - friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); - - bool isHidden() const; - bool throws() const; - bool okToFail() const; - bool expectedToFail() const; - - std::string tagsAsString() const; - - std::string name; - std::string className; - std::string description; - std::vector tags; - std::vector lcaseTags; - SourceLineInfo lineInfo; - SpecialProperties properties; - }; - - class TestCase : public TestCaseInfo { - public: - - TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); - - TestCase withName( std::string const& _newName ) const; - - void invoke() const; - - TestCaseInfo const& getTestCaseInfo() const; - - bool operator == ( TestCase const& other ) const; - bool operator < ( TestCase const& other ) const; - - private: - std::shared_ptr test; - }; - - TestCase makeTestCase( ITestInvoker* testCase, - std::string const& className, - NameAndTags const& nameAndTags, - SourceLineInfo const& lineInfo ); -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_test_case_info.h -// start catch_interfaces_runner.h - -namespace Catch { - - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; - }; -} - -// end catch_interfaces_runner.h - -#ifdef __OBJC__ -// start catch_objc.hpp - -#import - -#include - -// NB. Any general catch headers included here must be included -// in catch.hpp first to make sure they are included by the single -// header for non obj-usage - -/////////////////////////////////////////////////////////////////////////////// -// This protocol is really only here for (self) documenting purposes, since -// all its methods are optional. -@protocol OcFixture - -@optional - --(void) setUp; --(void) tearDown; - -@end - -namespace Catch { - - class OcMethod : public ITestInvoker { - - public: - OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} - - virtual void invoke() const { - id obj = [[m_cls alloc] init]; - - performOptionalSelector( obj, @selector(setUp) ); - performOptionalSelector( obj, m_sel ); - performOptionalSelector( obj, @selector(tearDown) ); - - arcSafeRelease( obj ); - } - private: - virtual ~OcMethod() {} - - Class m_cls; - SEL m_sel; - }; - - namespace Detail{ - - inline std::string getAnnotation( Class cls, - std::string const& annotationName, - std::string const& testCaseName ) { - NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; - SEL sel = NSSelectorFromString( selStr ); - arcSafeRelease( selStr ); - id value = performOptionalSelector( cls, sel ); - if( value ) - return [(NSString*)value UTF8String]; - return ""; - } - } - - inline std::size_t registerTestMethods() { - std::size_t noTestMethods = 0; - int noClasses = objc_getClassList( nullptr, 0 ); - - Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); - objc_getClassList( classes, noClasses ); - - for( int c = 0; c < noClasses; c++ ) { - Class cls = classes[c]; - { - u_int count; - Method* methods = class_copyMethodList( cls, &count ); - for( u_int m = 0; m < count ; m++ ) { - SEL selector = method_getName(methods[m]); - std::string methodName = sel_getName(selector); - if( startsWith( methodName, "Catch_TestCase_" ) ) { - std::string testCaseName = methodName.substr( 15 ); - std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); - std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); - const char* className = class_getName( cls ); - - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); - noTestMethods++; - } - } - free(methods); - } - } - return noTestMethods; - } - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - - namespace Matchers { - namespace Impl { - namespace NSStringMatchers { - - struct StringHolder : MatcherBase{ - StringHolder( NSString* substr ) : m_substr( [substr copy] ){} - StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} - StringHolder() { - arcSafeRelease( m_substr ); - } - - bool match( NSString* arg ) const override { - return false; - } - - NSString* CATCH_ARC_STRONG m_substr; - }; - - struct Equals : StringHolder { - Equals( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str isEqualToString:m_substr]; - } - - std::string describe() const override { - return "equals string: " + Catch::Detail::stringify( m_substr ); - } - }; - - struct Contains : StringHolder { - Contains( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location != NSNotFound; - } - - std::string describe() const override { - return "contains string: " + Catch::Detail::stringify( m_substr ); - } - }; - - struct StartsWith : StringHolder { - StartsWith( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == 0; - } - - std::string describe() const override { - return "starts with: " + Catch::Detail::stringify( m_substr ); - } - }; - struct EndsWith : StringHolder { - EndsWith( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == [str length] - [m_substr length]; - } - - std::string describe() const override { - return "ends with: " + Catch::Detail::stringify( m_substr ); - } - }; - - } // namespace NSStringMatchers - } // namespace Impl - - inline Impl::NSStringMatchers::Equals - Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } - - inline Impl::NSStringMatchers::Contains - Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } - - inline Impl::NSStringMatchers::StartsWith - StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } - - inline Impl::NSStringMatchers::EndsWith - EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } - - } // namespace Matchers - - using namespace Matchers; - -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -} // namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix -#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ -+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ -{ \ -return @ name; \ -} \ -+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ -{ \ -return @ desc; \ -} \ --(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) - -#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) - -// end catch_objc.hpp -#endif - -#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES -// start catch_external_interfaces.h - -// start catch_reporter_bases.hpp - -// start catch_interfaces_reporter.h - -// start catch_config.hpp - -// start catch_test_spec_parser.h - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -// start catch_test_spec.h - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -// start catch_wildcard_pattern.h - -namespace Catch -{ - class WildcardPattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - - public: - - WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); - virtual ~WildcardPattern() = default; - virtual bool matches( std::string const& str ) const; - - private: - std::string adjustCase( std::string const& str ) const; - CaseSensitive::Choice m_caseSensitivity; - WildcardPosition m_wildcard = NoWildcard; - std::string m_pattern; - }; -} - -// end catch_wildcard_pattern.h -#include -#include -#include - -namespace Catch { - - class TestSpec { - struct Pattern { - virtual ~Pattern(); - virtual bool matches( TestCaseInfo const& testCase ) const = 0; - }; - using PatternPtr = std::shared_ptr; - - class NamePattern : public Pattern { - public: - NamePattern( std::string const& name ); - virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - WildcardPattern m_wildcardPattern; - }; - - class TagPattern : public Pattern { - public: - TagPattern( std::string const& tag ); - virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - std::string m_tag; - }; - - class ExcludedPattern : public Pattern { - public: - ExcludedPattern( PatternPtr const& underlyingPattern ); - virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - PatternPtr m_underlyingPattern; - }; - - struct Filter { - std::vector m_patterns; - - bool matches( TestCaseInfo const& testCase ) const; - }; - - public: - bool hasFilters() const; - bool matches( TestCaseInfo const& testCase ) const; - - private: - std::vector m_filters; - - friend class TestSpecParser; - }; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_test_spec.h -// start catch_interfaces_tag_alias_registry.h - -#include - -namespace Catch { - - struct TagAlias; - - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - // Nullptr if not present - virtual TagAlias const* find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - - static ITagAliasRegistry const& get(); - }; - -} // end namespace Catch - -// end catch_interfaces_tag_alias_registry.h -namespace Catch { - - class TestSpecParser { - enum Mode{ None, Name, QuotedName, Tag, EscapedName }; - Mode m_mode = None; - bool m_exclusion = false; - std::size_t m_start = std::string::npos, m_pos = 0; - std::string m_arg; - std::vector m_escapeChars; - TestSpec::Filter m_currentFilter; - TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases = nullptr; - - public: - TestSpecParser( ITagAliasRegistry const& tagAliases ); - - TestSpecParser& parse( std::string const& arg ); - TestSpec testSpec(); - - private: - void visitChar( char c ); - void startNewMode( Mode mode, std::size_t start ); - void escape(); - std::string subString() const; - - template - void addPattern() { - std::string token = subString(); - for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) - token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); - m_escapeChars.clear(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - TestSpec::PatternPtr pattern = std::make_shared( token ); - if( m_exclusion ) - pattern = std::make_shared( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); - } - m_exclusion = false; - m_mode = None; - } - - void addFilter(); - }; - TestSpec parseTestSpec( std::string const& arg ); - -} // namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_test_spec_parser.h -// start catch_interfaces_config.h - -#include -#include -#include -#include - -namespace Catch { - - enum class Verbosity { - Quiet = 0, - Normal, - High - }; - - struct WarnAbout { enum What { - Nothing = 0x00, - NoAssertions = 0x01, - NoTests = 0x02 - }; }; - - struct ShowDurations { enum OrNot { - DefaultForReporter, - Always, - Never - }; }; - struct RunTests { enum InWhatOrder { - InDeclarationOrder, - InLexicographicalOrder, - InRandomOrder - }; }; - struct UseColour { enum YesOrNo { - Auto, - Yes, - No - }; }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; - - class TestSpec; - - struct IConfig : NonCopyable { - - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual std::ostream& stream() const = 0; - virtual std::string name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual bool warnAboutNoTests() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations::OrNot showDurations() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual bool hasTestFilters() const = 0; - virtual RunTests::InWhatOrder runOrder() const = 0; - virtual unsigned int rngSeed() const = 0; - virtual int benchmarkResolutionMultiple() const = 0; - virtual UseColour::YesOrNo useColour() const = 0; - virtual std::vector const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - }; - - using IConfigPtr = std::shared_ptr; -} - -// end catch_interfaces_config.h -// Libstdc++ doesn't like incomplete classes for unique_ptr - -#include -#include -#include - -#ifndef CATCH_CONFIG_CONSOLE_WIDTH -#define CATCH_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { - - struct IStream; - - struct ConfigData { - bool listTests = false; - bool listTags = false; - bool listReporters = false; - bool listTestNamesOnly = false; - - bool showSuccessfulTests = false; - bool shouldDebugBreak = false; - bool noThrow = false; - bool showHelp = false; - bool showInvisibles = false; - bool filenamesAsTags = false; - bool libIdentify = false; - - int abortAfter = -1; - unsigned int rngSeed = 0; - int benchmarkResolutionMultiple = 100; - - Verbosity verbosity = Verbosity::Normal; - WarnAbout::What warnings = WarnAbout::Nothing; - ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; - RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; - UseColour::YesOrNo useColour = UseColour::Auto; - WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; - - std::string outputFilename; - std::string name; - std::string processName; -#ifndef CATCH_CONFIG_DEFAULT_REPORTER -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif - std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; -#undef CATCH_CONFIG_DEFAULT_REPORTER - - std::vector testsOrTags; - std::vector sectionsToRun; - }; - - class Config : public IConfig { - public: - - Config() = default; - Config( ConfigData const& data ); - virtual ~Config() = default; - - std::string const& getFilename() const; - - bool listTests() const; - bool listTestNamesOnly() const; - bool listTags() const; - bool listReporters() const; - - std::string getProcessName() const; - std::string const& getReporterName() const; - - std::vector const& getTestsOrTags() const; - std::vector const& getSectionsToRun() const override; - - virtual TestSpec const& testSpec() const override; - bool hasTestFilters() const override; - - bool showHelp() const; - - // IConfig interface - bool allowThrows() const override; - std::ostream& stream() const override; - std::string name() const override; - bool includeSuccessfulResults() const override; - bool warnAboutMissingAssertions() const override; - bool warnAboutNoTests() const override; - ShowDurations::OrNot showDurations() const override; - RunTests::InWhatOrder runOrder() const override; - unsigned int rngSeed() const override; - int benchmarkResolutionMultiple() const override; - UseColour::YesOrNo useColour() const override; - bool shouldDebugBreak() const override; - int abortAfter() const override; - bool showInvisibles() const override; - Verbosity verbosity() const override; - - private: - - IStream const* openStream(); - ConfigData m_data; - - std::unique_ptr m_stream; - TestSpec m_testSpec; - bool m_hasTestFilters = false; - }; - -} // end namespace Catch - -// end catch_config.hpp -// start catch_assertionresult.h - -#include - -namespace Catch { - - struct AssertionResultData - { - AssertionResultData() = delete; - - AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - - std::string message; - mutable std::string reconstructedExpression; - LazyExpression lazyExpression; - ResultWas::OfType resultType; - - std::string reconstructExpression() const; - }; - - class AssertionResult { - public: - AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - StringRef getTestMacroName() const; - - //protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -// end catch_assertionresult.h -// start catch_option.hpp - -namespace Catch { - - // An optional type - template - class Option { - public: - Option() : nullableValue( nullptr ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} - - ~Option() { - reset(); - } - - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } - - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = nullptr; - } - - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } - - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } - - bool some() const { return nullableValue != nullptr; } - bool none() const { return nullableValue == nullptr; } - - bool operator !() const { return nullableValue == nullptr; } - explicit operator bool() const { - return some(); - } - - private: - T *nullableValue; - alignas(alignof(T)) char storage[sizeof(T)]; - }; - -} // end namespace Catch - -// end catch_option.hpp -#include -#include -#include -#include -#include - -namespace Catch { - - struct ReporterConfig { - explicit ReporterConfig( IConfigPtr const& _fullConfig ); - - ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); - - std::ostream& stream() const; - IConfigPtr fullConfig() const; - - private: - std::ostream* m_stream; - IConfigPtr m_fullConfig; - }; - - struct ReporterPreferences { - bool shouldRedirectStdOut = false; - bool shouldReportAllAssertions = false; - }; - - template - struct LazyStat : Option { - LazyStat& operator=( T const& _value ) { - Option::operator=( _value ); - used = false; - return *this; - } - void reset() { - Option::reset(); - used = false; - } - bool used = false; - }; - - struct TestRunInfo { - TestRunInfo( std::string const& _name ); - std::string name; - }; - struct GroupInfo { - GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ); - - std::string name; - std::size_t groupIndex; - std::size_t groupsCounts; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ); - - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; - virtual ~AssertionStats(); - - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ); - SectionStats( SectionStats const& ) = default; - SectionStats( SectionStats && ) = default; - SectionStats& operator = ( SectionStats const& ) = default; - SectionStats& operator = ( SectionStats && ) = default; - virtual ~SectionStats(); - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; - - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ); - - TestCaseStats( TestCaseStats const& ) = default; - TestCaseStats( TestCaseStats && ) = default; - TestCaseStats& operator = ( TestCaseStats const& ) = default; - TestCaseStats& operator = ( TestCaseStats && ) = default; - virtual ~TestCaseStats(); - - TestCaseInfo testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; - - struct TestGroupStats { - TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ); - TestGroupStats( GroupInfo const& _groupInfo ); - - TestGroupStats( TestGroupStats const& ) = default; - TestGroupStats( TestGroupStats && ) = default; - TestGroupStats& operator = ( TestGroupStats const& ) = default; - TestGroupStats& operator = ( TestGroupStats && ) = default; - virtual ~TestGroupStats(); - - GroupInfo groupInfo; - Totals totals; - bool aborting; - }; - - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ); - - TestRunStats( TestRunStats const& ) = default; - TestRunStats( TestRunStats && ) = default; - TestRunStats& operator = ( TestRunStats const& ) = default; - TestRunStats& operator = ( TestRunStats && ) = default; - virtual ~TestRunStats(); - - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; - - struct BenchmarkInfo { - std::string name; - }; - struct BenchmarkStats { - BenchmarkInfo info; - std::size_t iterations; - uint64_t elapsedTimeInNanoseconds; - }; - - struct IStreamingReporter { - virtual ~IStreamingReporter() = default; - - // Implementing class must also provide the following static methods: - // static std::string getDescription(); - // static std::set getSupportedVerbosities() - - virtual ReporterPreferences getPreferences() const = 0; - - virtual void noMatchingTestCases( std::string const& spec ) = 0; - - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - // *** experimental *** - virtual void benchmarkStarting( BenchmarkInfo const& ) {} - - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - - // *** experimental *** - virtual void benchmarkEnded( BenchmarkStats const& ) {} - - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - - // Default empty implementation provided - virtual void fatalErrorEncountered( StringRef name ); - - virtual bool isMulti() const; - }; - using IStreamingReporterPtr = std::unique_ptr; - - struct IReporterFactory { - virtual ~IReporterFactory(); - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; - virtual std::string getDescription() const = 0; - }; - using IReporterFactoryPtr = std::shared_ptr; - - struct IReporterRegistry { - using FactoryMap = std::map; - using Listeners = std::vector; - - virtual ~IReporterRegistry(); - virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; - }; - -} // end namespace Catch - -// end catch_interfaces_reporter.h -#include -#include -#include -#include -#include -#include -#include - -namespace Catch { - void prepareExpandedExpression(AssertionResult& result); - - // Returns double formatted as %.3f (format expected on output) - std::string getFormattedDuration( double duration ); - - template - struct StreamingReporterBase : IStreamingReporter { - - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) - CATCH_ERROR( "Verbosity level not supported by this reporter" ); - } - - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } - - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } - - ~StreamingReporterBase() override = default; - - void noMatchingTestCases(std::string const&) override {} - - void testRunStarting(TestRunInfo const& _testRunInfo) override { - currentTestRunInfo = _testRunInfo; - } - void testGroupStarting(GroupInfo const& _groupInfo) override { - currentGroupInfo = _groupInfo; - } - - void testCaseStarting(TestCaseInfo const& _testInfo) override { - currentTestCaseInfo = _testInfo; - } - void sectionStarting(SectionInfo const& _sectionInfo) override { - m_sectionStack.push_back(_sectionInfo); - } - - void sectionEnded(SectionStats const& /* _sectionStats */) override { - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { - currentTestCaseInfo.reset(); - } - void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { - currentGroupInfo.reset(); - } - void testRunEnded(TestRunStats const& /* _testRunStats */) override { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); - } - - void skipTest(TestCaseInfo const&) override { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } - - IConfigPtr m_config; - std::ostream& stream; - - LazyStat currentTestRunInfo; - LazyStat currentGroupInfo; - LazyStat currentTestCaseInfo; - - std::vector m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; - - template - struct CumulativeReporterBase : IStreamingReporter { - template - struct Node { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} - - using ChildNodes = std::vector>; - T value; - ChildNodes children; - }; - struct SectionNode { - explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} - virtual ~SectionNode() = default; - - bool operator == (SectionNode const& other) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; - } - bool operator == (std::shared_ptr const& other) const { - return operator==(*other); - } - - SectionStats stats; - using ChildSections = std::vector>; - using Assertions = std::vector; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; - }; - - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() (std::shared_ptr const& node) const { - return ((node->stats.sectionInfo.name == m_other.name) && - (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); - } - void operator=(BySectionInfo const&) = delete; - - private: - SectionInfo const& m_other; - }; - - using TestCaseNode = Node; - using TestGroupNode = Node; - using TestRunNode = Node; - - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) - CATCH_ERROR( "Verbosity level not supported by this reporter" ); - } - ~CumulativeReporterBase() override = default; - - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } - - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } - - void testRunStarting( TestRunInfo const& ) override {} - void testGroupStarting( GroupInfo const& ) override {} - - void testCaseStarting( TestCaseInfo const& ) override {} - - void sectionStarting( SectionInfo const& sectionInfo ) override { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - std::shared_ptr node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = std::make_shared( incompleteStats ); - node = m_rootSection; - } - else { - SectionNode& parentNode = *m_sectionStack.back(); - auto it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = std::make_shared( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; - } - m_sectionStack.push_back( node ); - m_deepestSection = std::move(node); - } - - void assertionStarting(AssertionInfo const&) override {} - - bool assertionEnded(AssertionStats const& assertionStats) override { - assert(!m_sectionStack.empty()); - // AssertionResult holds a pointer to a temporary DecomposedExpression, - // which getExpandedExpression() calls to build the expression string. - // Our section stack copy of the assertionResult will likely outlive the - // temporary, so it must be expanded or discarded now to avoid calling - // a destroyed object later. - prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back(assertionStats); - return true; - } - void sectionEnded(SectionStats const& sectionStats) override { - assert(!m_sectionStack.empty()); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& testCaseStats) override { - auto node = std::make_shared(testCaseStats); - assert(m_sectionStack.size() == 0); - node->children.push_back(m_rootSection); - m_testCases.push_back(node); - m_rootSection.reset(); - - assert(m_deepestSection); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - void testGroupEnded(TestGroupStats const& testGroupStats) override { - auto node = std::make_shared(testGroupStats); - node->children.swap(m_testCases); - m_testGroups.push_back(node); - } - void testRunEnded(TestRunStats const& testRunStats) override { - auto node = std::make_shared(testRunStats); - node->children.swap(m_testGroups); - m_testRuns.push_back(node); - testRunEndedCumulative(); - } - virtual void testRunEndedCumulative() = 0; - - void skipTest(TestCaseInfo const&) override {} - - IConfigPtr m_config; - std::ostream& stream; - std::vector m_assertions; - std::vector>> m_sections; - std::vector> m_testCases; - std::vector> m_testGroups; - - std::vector> m_testRuns; - - std::shared_ptr m_rootSection; - std::shared_ptr m_deepestSection; - std::vector> m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; - - template - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; - } - - struct TestEventListenerBase : StreamingReporterBase { - TestEventListenerBase( ReporterConfig const& _config ); - - void assertionStarting(AssertionInfo const&) override; - bool assertionEnded(AssertionStats const&) override; - }; - -} // end namespace Catch - -// end catch_reporter_bases.hpp -// start catch_console_colour.h - -namespace Catch { - - struct Colour { - enum Code { - None = 0, - - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, - BrightYellow = Bright | Yellow, - - // By intention - FileName = LightGrey, - Warning = BrightYellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, - - Error = BrightRed, - Success = Green, - - OriginalExpression = Cyan, - ReconstructedExpression = BrightYellow, - - SecondaryText = LightGrey, - Headers = White - }; - - // Use constructed object for RAII guard - Colour( Code _colourCode ); - Colour( Colour&& other ) noexcept; - Colour& operator=( Colour&& other ) noexcept; - ~Colour(); - - // Use static method for one-shot changes - static void use( Code _colourCode ); - - private: - bool m_moved = false; - }; - - std::ostream& operator << ( std::ostream& os, Colour const& ); - -} // end namespace Catch - -// end catch_console_colour.h -// start catch_reporter_registrars.hpp - - -namespace Catch { - - template - class ReporterRegistrar { - - class ReporterFactory : public IReporterFactory { - - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } - - virtual std::string getDescription() const override { - return T::getDescription(); - } - }; - - public: - - explicit ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, std::make_shared() ); - } - }; - - template - class ListenerRegistrar { - - class ListenerFactory : public IReporterFactory { - - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } - virtual std::string getDescription() const override { - return std::string(); - } - }; - - public: - - ListenerRegistrar() { - getMutableRegistryHub().registerListener( std::make_shared() ); - } - }; -} - -#if !defined(CATCH_CONFIG_DISABLE) - -#define CATCH_REGISTER_REPORTER( name, reporterType ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - -#define CATCH_REGISTER_LISTENER( listenerType ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#else // CATCH_CONFIG_DISABLE - -#define CATCH_REGISTER_REPORTER(name, reporterType) -#define CATCH_REGISTER_LISTENER(listenerType) - -#endif // CATCH_CONFIG_DISABLE - -// end catch_reporter_registrars.hpp -// Allow users to base their work off existing reporters -// start catch_reporter_compact.h - -namespace Catch { - - struct CompactReporter : StreamingReporterBase { - - using StreamingReporterBase::StreamingReporterBase; - - ~CompactReporter() override; - - static std::string getDescription(); - - ReporterPreferences getPreferences() const override; - - void noMatchingTestCases(std::string const& spec) override; - - void assertionStarting(AssertionInfo const&) override; - - bool assertionEnded(AssertionStats const& _assertionStats) override; - - void sectionEnded(SectionStats const& _sectionStats) override; - - void testRunEnded(TestRunStats const& _testRunStats) override; - - }; - -} // end namespace Catch - -// end catch_reporter_compact.h -// start catch_reporter_console.h - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif - -namespace Catch { - // Fwd decls - struct SummaryColumn; - class TablePrinter; - - struct ConsoleReporter : StreamingReporterBase { - std::unique_ptr m_tablePrinter; - - ConsoleReporter(ReporterConfig const& config); - ~ConsoleReporter() override; - static std::string getDescription(); - - void noMatchingTestCases(std::string const& spec) override; - - void assertionStarting(AssertionInfo const&) override; - - bool assertionEnded(AssertionStats const& _assertionStats) override; - - void sectionStarting(SectionInfo const& _sectionInfo) override; - void sectionEnded(SectionStats const& _sectionStats) override; - - void benchmarkStarting(BenchmarkInfo const& info) override; - void benchmarkEnded(BenchmarkStats const& stats) override; - - void testCaseEnded(TestCaseStats const& _testCaseStats) override; - void testGroupEnded(TestGroupStats const& _testGroupStats) override; - void testRunEnded(TestRunStats const& _testRunStats) override; - - private: - - void lazyPrint(); - - void lazyPrintWithoutClosingBenchmarkTable(); - void lazyPrintRunInfo(); - void lazyPrintGroupInfo(); - void printTestCaseAndSectionHeader(); - - void printClosedHeader(std::string const& _name); - void printOpenHeader(std::string const& _name); - - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString(std::string const& _string, std::size_t indent = 0); - - void printTotals(Totals const& totals); - void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); - - void printTotalsDivider(Totals const& totals); - void printSummaryDivider(); - - private: - bool m_headerPrinted = false; - }; - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -// end catch_reporter_console.h -// start catch_reporter_junit.h - -// start catch_xmlwriter.h - -#include - -namespace Catch { - - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; - - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - - void encodeTo( std::ostream& os ) const; - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - - private: - std::string m_str; - ForWhat m_forWhat; - }; - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ); - - ScopedElement( ScopedElement&& other ) noexcept; - ScopedElement& operator=( ScopedElement&& other ) noexcept; - - ~ScopedElement(); - - ScopedElement& writeText( std::string const& text, bool indent = true ); - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer = nullptr; - }; - - XmlWriter( std::ostream& os = Catch::cout() ); - ~XmlWriter(); - - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; - - XmlWriter& startElement( std::string const& name ); - - ScopedElement scopedElement( std::string const& name ); - - XmlWriter& endElement(); - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - - XmlWriter& writeAttribute( std::string const& name, bool attribute ); - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - ReusableStringStream rss; - rss << attribute; - return writeAttribute( name, rss.str() ); - } - - XmlWriter& writeText( std::string const& text, bool indent = true ); - - XmlWriter& writeComment( std::string const& text ); - - void writeStylesheetRef( std::string const& url ); - - XmlWriter& writeBlankLine(); - - void ensureTagClosed(); - - private: - - void writeDeclaration(); - - void newlineIfNecessary(); - - bool m_tagIsOpen = false; - bool m_needsNewline = false; - std::vector m_tags; - std::string m_indent; - std::ostream& m_os; - }; - -} - -// end catch_xmlwriter.h -namespace Catch { - - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter(ReporterConfig const& _config); - - ~JunitReporter() override; - - static std::string getDescription(); - - void noMatchingTestCases(std::string const& /*spec*/) override; - - void testRunStarting(TestRunInfo const& runInfo) override; - - void testGroupStarting(GroupInfo const& groupInfo) override; - - void testCaseStarting(TestCaseInfo const& testCaseInfo) override; - bool assertionEnded(AssertionStats const& assertionStats) override; - - void testCaseEnded(TestCaseStats const& testCaseStats) override; - - void testGroupEnded(TestGroupStats const& testGroupStats) override; - - void testRunEndedCumulative() override; - - void writeGroup(TestGroupNode const& groupNode, double suiteTime); - - void writeTestCase(TestCaseNode const& testCaseNode); - - void writeSection(std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode); - - void writeAssertions(SectionNode const& sectionNode); - void writeAssertion(AssertionStats const& stats); - - XmlWriter xml; - Timer suiteTimer; - std::string stdOutForSuite; - std::string stdErrForSuite; - unsigned int unexpectedExceptions = 0; - bool m_okToFail = false; - }; - -} // end namespace Catch - -// end catch_reporter_junit.h -// start catch_reporter_xml.h - -namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter(ReporterConfig const& _config); - - ~XmlReporter() override; - - static std::string getDescription(); - - virtual std::string getStylesheetRef() const; - - void writeSourceInfo(SourceLineInfo const& sourceInfo); - - public: // StreamingReporterBase - - void noMatchingTestCases(std::string const& s) override; - - void testRunStarting(TestRunInfo const& testInfo) override; - - void testGroupStarting(GroupInfo const& groupInfo) override; - - void testCaseStarting(TestCaseInfo const& testInfo) override; - - void sectionStarting(SectionInfo const& sectionInfo) override; - - void assertionStarting(AssertionInfo const&) override; - - bool assertionEnded(AssertionStats const& assertionStats) override; - - void sectionEnded(SectionStats const& sectionStats) override; - - void testCaseEnded(TestCaseStats const& testCaseStats) override; - - void testGroupEnded(TestGroupStats const& testGroupStats) override; - - void testRunEnded(TestRunStats const& testRunStats) override; - - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth = 0; - }; - -} // end namespace Catch - -// end catch_reporter_xml.h - -// end catch_external_interfaces.h -#endif - -#endif // ! CATCH_CONFIG_IMPL_ONLY - -#ifdef CATCH_IMPL -// start catch_impl.hpp - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif - -// Keep these here for external reporters -// start catch_test_case_tracker.h - -#include -#include -#include - -namespace Catch { -namespace TestCaseTracking { - - struct NameAndLocation { - std::string name; - SourceLineInfo location; - - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); - }; - - struct ITracker; - - using ITrackerPtr = std::shared_ptr; - - struct ITracker { - virtual ~ITracker(); - - // static queries - virtual NameAndLocation const& nameAndLocation() const = 0; - - // dynamic queries - virtual bool isComplete() const = 0; // Successfully completed or failed - virtual bool isSuccessfullyCompleted() const = 0; - virtual bool isOpen() const = 0; // Started but not complete - virtual bool hasChildren() const = 0; - - virtual ITracker& parent() = 0; - - // actions - virtual void close() = 0; // Successfully complete - virtual void fail() = 0; - virtual void markAsNeedingAnotherRun() = 0; - - virtual void addChild( ITrackerPtr const& child ) = 0; - virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; - virtual void openChild() = 0; - - // Debug/ checking - virtual bool isSectionTracker() const = 0; - virtual bool isIndexTracker() const = 0; - }; - - class TrackerContext { - - enum RunState { - NotStarted, - Executing, - CompletedCycle - }; - - ITrackerPtr m_rootTracker; - ITracker* m_currentTracker = nullptr; - RunState m_runState = NotStarted; - - public: - - static TrackerContext& instance(); - - ITracker& startRun(); - void endRun(); - - void startCycle(); - void completeCycle(); - - bool completedCycle() const; - ITracker& currentTracker(); - void setCurrentTracker( ITracker* tracker ); - }; - - class TrackerBase : public ITracker { - protected: - enum CycleState { - NotStarted, - Executing, - ExecutingChildren, - NeedsAnotherRun, - CompletedSuccessfully, - Failed - }; - - using Children = std::vector; - NameAndLocation m_nameAndLocation; - TrackerContext& m_ctx; - ITracker* m_parent; - Children m_children; - CycleState m_runState = NotStarted; - - public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - - NameAndLocation const& nameAndLocation() const override; - bool isComplete() const override; - bool isSuccessfullyCompleted() const override; - bool isOpen() const override; - bool hasChildren() const override; - - void addChild( ITrackerPtr const& child ) override; - - ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; - ITracker& parent() override; - - void openChild() override; - - bool isSectionTracker() const override; - bool isIndexTracker() const override; - - void open(); - - void close() override; - void fail() override; - void markAsNeedingAnotherRun() override; - - private: - void moveToParent(); - void moveToThis(); - }; - - class SectionTracker : public TrackerBase { - std::vector m_filters; - public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - - bool isSectionTracker() const override; - - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); - - void tryOpen(); - - void addInitialFilters( std::vector const& filters ); - void addNextFilters( std::vector const& filters ); - }; - - class IndexTracker : public TrackerBase { - int m_size; - int m_index = -1; - public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); - - bool isIndexTracker() const override; - void close() override; - - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); - - int index() const; - - void moveNext(); - }; - -} // namespace TestCaseTracking - -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; - -} // namespace Catch - -// end catch_test_case_tracker.h - -// start catch_leak_detector.h - -namespace Catch { - - struct LeakDetector { - LeakDetector(); - }; - -} -// end catch_leak_detector.h -// Cpp files will be included in the single-header file here -// start catch_approx.cpp - -#include -#include - -namespace { - -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { - return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} - -} - -namespace Catch { -namespace Detail { - - Approx::Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_margin( 0.0 ), - m_scale( 0.0 ), - m_value( value ) - {} - - Approx Approx::custom() { - return Approx( 0 ); - } - - Approx Approx::operator-() const { - auto temp(*this); - temp.m_value = -temp.m_value; - return temp; - } - - std::string Approx::toString() const { - ReusableStringStream rss; - rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; - return rss.str(); - } - - bool Approx::equalityComparisonImpl(const double other) const { - // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value - // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); - } - - void Approx::setMargin(double margin) { - CATCH_ENFORCE(margin >= 0, - "Invalid Approx::margin: " << margin << '.' - << " Approx::Margin has to be non-negative."); - m_margin = margin; - } - - void Approx::setEpsilon(double epsilon) { - CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0, - "Invalid Approx::epsilon: " << epsilon << '.' - << " Approx::epsilon has to be in [0, 1]"); - m_epsilon = epsilon; - } - -} // end namespace Detail - -namespace literals { - Detail::Approx operator "" _a(long double val) { - return Detail::Approx(val); - } - Detail::Approx operator "" _a(unsigned long long val) { - return Detail::Approx(val); - } -} // end namespace literals - -std::string StringMaker::convert(Catch::Detail::Approx const& value) { - return value.toString(); -} - -} // end namespace Catch -// end catch_approx.cpp -// start catch_assertionhandler.cpp - -// start catch_context.h - -#include - -namespace Catch { - - struct IResultCapture; - struct IRunner; - struct IConfig; - struct IMutableContext; - - using IConfigPtr = std::shared_ptr; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual IConfigPtr const& getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( IConfigPtr const& config ) = 0; - - private: - static IMutableContext *currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); - static void createContext(); - }; - - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - return *IMutableContext::currentContext; - } - - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); - } - - void cleanUpContext(); -} - -// end catch_context.h -// start catch_debugger.h - -namespace Catch { - bool isDebuggerActive(); -} - -#ifdef CATCH_PLATFORM_MAC - - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ - -#elif defined(CATCH_PLATFORM_LINUX) - // If we can use inline assembler, do it because this allows us to break - // directly at the location of the failing check instead of breaking inside - // raise() called from it, i.e. one stack frame below. - #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) - #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ - #else // Fall back to the generic way. - #include - - #define CATCH_TRAP() raise(SIGTRAP) - #endif -#elif defined(_MSC_VER) - #define CATCH_TRAP() __debugbreak() -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_TRAP() DebugBreak() -#endif - -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } -#else - namespace Catch { - inline void doNothing() {} - } - #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() -#endif - -// end catch_debugger.h -// start catch_run_context.h - -// start catch_fatal_condition.h - -// start catch_windows_h_proxy.h - - -#if defined(CATCH_PLATFORM_WINDOWS) - -#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX -# define NOMINMAX -#endif -#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - -#ifdef CATCH_DEFINED_NOMINMAX -# undef NOMINMAX -#endif -#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif - -#endif // defined(CATCH_PLATFORM_WINDOWS) - -// end catch_windows_h_proxy.h -#if defined( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); - FatalConditionHandler(); - static void reset(); - ~FatalConditionHandler(); - - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - -} // namespace Catch - -#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) - -#include - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); - - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); - }; - -} // namespace Catch - -#else - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -#endif - -// end catch_fatal_condition.h -#include - -namespace Catch { - - struct IMutableContext; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - public: - RunContext( RunContext const& ) = delete; - RunContext& operator =( RunContext const& ) = delete; - - explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); - - ~RunContext() override; - - void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); - void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); - - Totals runTest(TestCase const& testCase); - - IConfigPtr config() const; - IStreamingReporter& reporter() const; - - public: // IResultCapture - - // Assertion handlers - void handleExpr - ( AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction ) override; - void handleMessage - ( AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef const& message, - AssertionReaction& reaction ) override; - void handleUnexpectedExceptionNotThrown - ( AssertionInfo const& info, - AssertionReaction& reaction ) override; - void handleUnexpectedInflightException - ( AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction ) override; - void handleIncomplete - ( AssertionInfo const& info ) override; - void handleNonExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction ) override; - - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; - - void sectionEnded( SectionEndInfo const& endInfo ) override; - void sectionEndedEarly( SectionEndInfo const& endInfo ) override; - - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; - - void benchmarkStarting( BenchmarkInfo const& info ) override; - void benchmarkEnded( BenchmarkStats const& stats ) override; - - void pushScopedMessage( MessageInfo const& message ) override; - void popScopedMessage( MessageInfo const& message ) override; - - std::string getCurrentTestName() const override; - - const AssertionResult* getLastResult() const override; - - void exceptionEarlyReported() override; - - void handleFatalErrorCondition( StringRef message ) override; - - bool lastAssertionPassed() override; - - void assertionPassed() override; - - public: - // !TBD We need to do this another way! - bool aborting() const final; - - private: - - void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); - void invokeActiveTestCase(); - - void resetAssertionInfo(); - bool testForMissingAssertions( Counts& assertions ); - - void assertionEnded( AssertionResult const& result ); - void reportExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - ITransientExpression const *expr, - bool negated ); - - void populateReaction( AssertionReaction& reaction ); - - private: - - void handleUnfinishedSections(); - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase = nullptr; - ITracker* m_testCaseTracker; - Option m_lastResult; - - IConfigPtr m_config; - Totals m_totals; - IStreamingReporterPtr m_reporter; - std::vector m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - std::vector m_activeSections; - TrackerContext m_trackerContext; - bool m_lastAssertionPassed = false; - bool m_shouldReportUnexpected = true; - bool m_includeSuccessfulResults; - }; - -} // end namespace Catch - -// end catch_run_context.h -namespace Catch { - - namespace { - auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { - expr.streamReconstructedExpression( os ); - return os; - } - } - - LazyExpression::LazyExpression( bool isNegated ) - : m_isNegated( isNegated ) - {} - - LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} - - LazyExpression::operator bool() const { - return m_transientExpression != nullptr; - } - - auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { - if( lazyExpr.m_isNegated ) - os << "!"; - - if( lazyExpr ) { - if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) - os << "(" << *lazyExpr.m_transientExpression << ")"; - else - os << *lazyExpr.m_transientExpression; - } - else { - os << "{** error - unchecked empty expression requested **}"; - } - return os; - } - - AssertionHandler::AssertionHandler - ( StringRef const& macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, - m_resultCapture( getResultCapture() ) - {} - - void AssertionHandler::handleExpr( ITransientExpression const& expr ) { - m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); - } - void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { - m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); - } - - auto AssertionHandler::allowThrows() const -> bool { - return getCurrentContext().getConfig()->allowThrows(); - } - - void AssertionHandler::complete() { - setCompleted(); - if( m_reaction.shouldDebugBreak ) { - - // If you find your debugger stopping you here then go one level up on the - // call-stack for the code that caused it (typically a failed assertion) - - // (To go back to the test and change execution, jump over the throw, next) - CATCH_BREAK_INTO_DEBUGGER(); - } - if (m_reaction.shouldThrow) { -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - throw Catch::TestFailureException(); -#else - CATCH_ERROR( "Test failure requires aborting test!" ); -#endif - } - } - void AssertionHandler::setCompleted() { - m_completed = true; - } - - void AssertionHandler::handleUnexpectedInflightException() { - m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); - } - - void AssertionHandler::handleExceptionThrownAsExpected() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - void AssertionHandler::handleExceptionNotThrownAsExpected() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - - void AssertionHandler::handleUnexpectedExceptionNotThrown() { - m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); - } - - void AssertionHandler::handleThrowingCallSkipped() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - - // This is the overload that takes a string and infers the Equals matcher from it - // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { - handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); - } - -} // namespace Catch -// end catch_assertionhandler.cpp -// start catch_assertionresult.cpp - -namespace Catch { - AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): - lazyExpression(_lazyExpression), - resultType(_resultType) {} - - std::string AssertionResultData::reconstructExpression() const { - - if( reconstructedExpression.empty() ) { - if( lazyExpression ) { - ReusableStringStream rss; - rss << lazyExpression; - reconstructedExpression = rss.str(); - } - } - return reconstructedExpression; - } - - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} - - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } - - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } - - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } - - bool AssertionResult::hasExpression() const { - return m_info.capturedExpression[0] != 0; - } - - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } - - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + m_info.capturedExpression + ")"; - else - return m_info.capturedExpression; - } - - std::string AssertionResult::getExpressionInMacro() const { - std::string expr; - if( m_info.macroName[0] == 0 ) - expr = m_info.capturedExpression; - else { - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; - } - return expr; - } - - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } - - std::string AssertionResult::getExpandedExpression() const { - std::string expr = m_resultData.reconstructExpression(); - return expr.empty() - ? getExpression() - : expr; - } - - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } - - StringRef AssertionResult::getTestMacroName() const { - return m_info.macroName; - } - -} // end namespace Catch -// end catch_assertionresult.cpp -// start catch_benchmark.cpp - -namespace Catch { - - auto BenchmarkLooper::getResolution() -> uint64_t { - return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); - } - - void BenchmarkLooper::reportStart() { - getResultCapture().benchmarkStarting( { m_name } ); - } - auto BenchmarkLooper::needsMoreIterations() -> bool { - auto elapsed = m_timer.getElapsedNanoseconds(); - - // Exponentially increasing iterations until we're confident in our timer resolution - if( elapsed < m_resolution ) { - m_iterationsToRun *= 10; - return true; - } - - getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); - return false; - } - -} // end namespace Catch -// end catch_benchmark.cpp -// start catch_capture_matchers.cpp - -namespace Catch { - - using StringMatcher = Matchers::Impl::MatcherBase; - - // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers - // the Equals matcher (so the header does not mention matchers) - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { - std::string exceptionMessage = Catch::translateActiveException(); - MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handleExpr( expr ); - } - -} // namespace Catch -// end catch_capture_matchers.cpp -// start catch_commandline.cpp - -// start catch_commandline.h - -// start catch_clara.h - -// Use Catch's value for console width (store Clara's off to the side, if present) -#ifdef CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#endif -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#pragma clang diagnostic ignored "-Wexit-time-destructors" -#pragma clang diagnostic ignored "-Wshadow" -#endif - -// start clara.hpp -// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See https://github.com/philsquared/Clara for more details - -// Clara v1.1.4 - - -#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 -#endif - -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -#ifndef CLARA_CONFIG_OPTIONAL_TYPE -#ifdef __has_include -#if __has_include() && __cplusplus >= 201703L -#include -#define CLARA_CONFIG_OPTIONAL_TYPE std::optional -#endif -#endif -#endif - -// ----------- #included from clara_textflow.hpp ----------- - -// TextFlowCpp -// -// A single-header library for wrapping and laying out basic text, by Phil Nash -// -// This work is licensed under the BSD 2-Clause license. -// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause -// -// This project is hosted at https://github.com/philsquared/textflowcpp - - -#include -#include -#include -#include - -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { namespace clara { namespace TextFlow { - - inline auto isWhitespace( char c ) -> bool { - static std::string chars = " \t\n\r"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableBefore( char c ) -> bool { - static std::string chars = "[({<|"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableAfter( char c ) -> bool { - static std::string chars = "])}>.,:;*+-=&/\\"; - return chars.find( c ) != std::string::npos; - } - - class Columns; - - class Column { - std::vector m_strings; - size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; - size_t m_indent = 0; - size_t m_initialIndent = std::string::npos; - - public: - class iterator { - friend Column; - - Column const& m_column; - size_t m_stringIndex = 0; - size_t m_pos = 0; - - size_t m_len = 0; - size_t m_end = 0; - bool m_suffix = false; - - iterator( Column const& column, size_t stringIndex ) - : m_column( column ), - m_stringIndex( stringIndex ) - {} - - auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } - - auto isBoundary( size_t at ) const -> bool { - assert( at > 0 ); - assert( at <= line().size() ); - - return at == line().size() || - ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || - isBreakableBefore( line()[at] ) || - isBreakableAfter( line()[at-1] ); - } - - void calcLength() { - assert( m_stringIndex < m_column.m_strings.size() ); - - m_suffix = false; - auto width = m_column.m_width-indent(); - m_end = m_pos; - while( m_end < line().size() && line()[m_end] != '\n' ) - ++m_end; - - if( m_end < m_pos + width ) { - m_len = m_end - m_pos; - } - else { - size_t len = width; - while (len > 0 && !isBoundary(m_pos + len)) - --len; - while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) - --len; - - if (len > 0) { - m_len = len; - } else { - m_suffix = true; - m_len = width - 1; - } - } - } - - auto indent() const -> size_t { - auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; - return initial == std::string::npos ? m_column.m_indent : initial; - } - - auto addIndentAndSuffix(std::string const &plain) const -> std::string { - return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); - } - - public: - explicit iterator( Column const& column ) : m_column( column ) { - assert( m_column.m_width > m_column.m_indent ); - assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); - calcLength(); - if( m_len == 0 ) - m_stringIndex++; // Empty string - } - - auto operator *() const -> std::string { - assert( m_stringIndex < m_column.m_strings.size() ); - assert( m_pos <= m_end ); - if( m_pos + m_column.m_width < m_end ) - return addIndentAndSuffix(line().substr(m_pos, m_len)); - else - return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); - } - - auto operator ++() -> iterator& { - m_pos += m_len; - if( m_pos < line().size() && line()[m_pos] == '\n' ) - m_pos += 1; - else - while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) - ++m_pos; - - if( m_pos == line().size() ) { - m_pos = 0; - ++m_stringIndex; - } - if( m_stringIndex < m_column.m_strings.size() ) - calcLength(); - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } - - auto operator ==( iterator const& other ) const -> bool { - return - m_pos == other.m_pos && - m_stringIndex == other.m_stringIndex && - &m_column == &other.m_column; - } - auto operator !=( iterator const& other ) const -> bool { - return !operator==( other ); - } - }; - using const_iterator = iterator; - - explicit Column( std::string const& text ) { m_strings.push_back( text ); } - - auto width( size_t newWidth ) -> Column& { - assert( newWidth > 0 ); - m_width = newWidth; - return *this; - } - auto indent( size_t newIndent ) -> Column& { - m_indent = newIndent; - return *this; - } - auto initialIndent( size_t newIndent ) -> Column& { - m_initialIndent = newIndent; - return *this; - } - - auto width() const -> size_t { return m_width; } - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, m_strings.size() }; } - - inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { - bool first = true; - for( auto line : col ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto operator + ( Column const& other ) -> Columns; - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; - - class Spacer : public Column { - - public: - explicit Spacer( size_t spaceWidth ) : Column( "" ) { - width( spaceWidth ); - } - }; - - class Columns { - std::vector m_columns; - - public: - - class iterator { - friend Columns; - struct EndTag {}; - - std::vector const& m_columns; - std::vector m_iterators; - size_t m_activeIterators; - - iterator( Columns const& columns, EndTag ) - : m_columns( columns.m_columns ), - m_activeIterators( 0 ) - { - m_iterators.reserve( m_columns.size() ); - - for( auto const& col : m_columns ) - m_iterators.push_back( col.end() ); - } - - public: - explicit iterator( Columns const& columns ) - : m_columns( columns.m_columns ), - m_activeIterators( m_columns.size() ) - { - m_iterators.reserve( m_columns.size() ); - - for( auto const& col : m_columns ) - m_iterators.push_back( col.begin() ); - } - - auto operator ==( iterator const& other ) const -> bool { - return m_iterators == other.m_iterators; - } - auto operator !=( iterator const& other ) const -> bool { - return m_iterators != other.m_iterators; - } - auto operator *() const -> std::string { - std::string row, padding; - - for( size_t i = 0; i < m_columns.size(); ++i ) { - auto width = m_columns[i].width(); - if( m_iterators[i] != m_columns[i].end() ) { - std::string col = *m_iterators[i]; - row += padding + col; - if( col.size() < width ) - padding = std::string( width - col.size(), ' ' ); - else - padding = ""; - } - else { - padding += std::string( width, ' ' ); - } - } - return row; - } - auto operator ++() -> iterator& { - for( size_t i = 0; i < m_columns.size(); ++i ) { - if (m_iterators[i] != m_columns[i].end()) - ++m_iterators[i]; - } - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } - }; - using const_iterator = iterator; - - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, iterator::EndTag() }; } - - auto operator += ( Column const& col ) -> Columns& { - m_columns.push_back( col ); - return *this; - } - auto operator + ( Column const& col ) -> Columns { - Columns combined = *this; - combined += col; - return combined; - } - - inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { - - bool first = true; - for( auto line : cols ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; - - inline auto Column::operator + ( Column const& other ) -> Columns { - Columns cols; - cols += *this; - cols += other; - return cols; - } -}}} // namespace Catch::clara::TextFlow - -// ----------- end of #include from clara_textflow.hpp ----------- -// ........... back in clara.hpp - -#include -#include -#include - -#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) -#define CATCH_PLATFORM_WINDOWS -#endif - -namespace Catch { namespace clara { -namespace detail { - - // Traits for extracting arg and return type of lambdas (for single argument lambdas) - template - struct UnaryLambdaTraits : UnaryLambdaTraits {}; - - template - struct UnaryLambdaTraits { - static const bool isValid = false; - }; - - template - struct UnaryLambdaTraits { - static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type; - using ReturnType = ReturnT; - }; - - class TokenStream; - - // Transport for raw args (copied from main args, or supplied via init list for testing) - class Args { - friend TokenStream; - std::string m_exeName; - std::vector m_args; - - public: - Args( int argc, char const* const* argv ) - : m_exeName(argv[0]), - m_args(argv + 1, argv + argc) {} - - Args( std::initializer_list args ) - : m_exeName( *args.begin() ), - m_args( args.begin()+1, args.end() ) - {} - - auto exeName() const -> std::string { - return m_exeName; - } - }; - - // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string - // may encode an option + its argument if the : or = form is used - enum class TokenType { - Option, Argument - }; - struct Token { - TokenType type; - std::string token; - }; - - inline auto isOptPrefix( char c ) -> bool { - return c == '-' -#ifdef CATCH_PLATFORM_WINDOWS - || c == '/' -#endif - ; - } - - // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled - class TokenStream { - using Iterator = std::vector::const_iterator; - Iterator it; - Iterator itEnd; - std::vector m_tokenBuffer; - - void loadBuffer() { - m_tokenBuffer.resize( 0 ); - - // Skip any empty strings - while( it != itEnd && it->empty() ) - ++it; - - if( it != itEnd ) { - auto const &next = *it; - if( isOptPrefix( next[0] ) ) { - auto delimiterPos = next.find_first_of( " :=" ); - if( delimiterPos != std::string::npos ) { - m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); - m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); - } else { - if( next[1] != '-' && next.size() > 2 ) { - std::string opt = "- "; - for( size_t i = 1; i < next.size(); ++i ) { - opt[1] = next[i]; - m_tokenBuffer.push_back( { TokenType::Option, opt } ); - } - } else { - m_tokenBuffer.push_back( { TokenType::Option, next } ); - } - } - } else { - m_tokenBuffer.push_back( { TokenType::Argument, next } ); - } - } - } - - public: - explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} - - TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { - loadBuffer(); - } - - explicit operator bool() const { - return !m_tokenBuffer.empty() || it != itEnd; - } - - auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } - - auto operator*() const -> Token { - assert( !m_tokenBuffer.empty() ); - return m_tokenBuffer.front(); - } - - auto operator->() const -> Token const * { - assert( !m_tokenBuffer.empty() ); - return &m_tokenBuffer.front(); - } - - auto operator++() -> TokenStream & { - if( m_tokenBuffer.size() >= 2 ) { - m_tokenBuffer.erase( m_tokenBuffer.begin() ); - } else { - if( it != itEnd ) - ++it; - loadBuffer(); - } - return *this; - } - }; - - class ResultBase { - public: - enum Type { - Ok, LogicError, RuntimeError - }; - - protected: - ResultBase( Type type ) : m_type( type ) {} - virtual ~ResultBase() = default; - - virtual void enforceOk() const = 0; - - Type m_type; - }; - - template - class ResultValueBase : public ResultBase { - public: - auto value() const -> T const & { - enforceOk(); - return m_value; - } - - protected: - ResultValueBase( Type type ) : ResultBase( type ) {} - - ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - } - - ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { - new( &m_value ) T( value ); - } - - auto operator=( ResultValueBase const &other ) -> ResultValueBase & { - if( m_type == ResultBase::Ok ) - m_value.~T(); - ResultBase::operator=(other); - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - return *this; - } - - ~ResultValueBase() override { - if( m_type == Ok ) - m_value.~T(); - } - - union { - T m_value; - }; - }; - - template<> - class ResultValueBase : public ResultBase { - protected: - using ResultBase::ResultBase; - }; - - template - class BasicResult : public ResultValueBase { - public: - template - explicit BasicResult( BasicResult const &other ) - : ResultValueBase( other.type() ), - m_errorMessage( other.errorMessage() ) - { - assert( type() != ResultBase::Ok ); - } - - template - static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } - static auto ok() -> BasicResult { return { ResultBase::Ok }; } - static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } - static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } - - explicit operator bool() const { return m_type == ResultBase::Ok; } - auto type() const -> ResultBase::Type { return m_type; } - auto errorMessage() const -> std::string { return m_errorMessage; } - - protected: - void enforceOk() const override { - - // Errors shouldn't reach this point, but if they do - // the actual error message will be in m_errorMessage - assert( m_type != ResultBase::LogicError ); - assert( m_type != ResultBase::RuntimeError ); - if( m_type != ResultBase::Ok ) - std::abort(); - } - - std::string m_errorMessage; // Only populated if resultType is an error - - BasicResult( ResultBase::Type type, std::string const &message ) - : ResultValueBase(type), - m_errorMessage(message) - { - assert( m_type != ResultBase::Ok ); - } - - using ResultValueBase::ResultValueBase; - using ResultBase::m_type; - }; - - enum class ParseResultType { - Matched, NoMatch, ShortCircuitAll, ShortCircuitSame - }; - - class ParseState { - public: - - ParseState( ParseResultType type, TokenStream const &remainingTokens ) - : m_type(type), - m_remainingTokens( remainingTokens ) - {} - - auto type() const -> ParseResultType { return m_type; } - auto remainingTokens() const -> TokenStream { return m_remainingTokens; } - - private: - ParseResultType m_type; - TokenStream m_remainingTokens; - }; - - using Result = BasicResult; - using ParserResult = BasicResult; - using InternalParseResult = BasicResult; - - struct HelpColumns { - std::string left; - std::string right; - }; - - template - inline auto convertInto( std::string const &source, T& target ) -> ParserResult { - std::stringstream ss; - ss << source; - ss >> target; - if( ss.fail() ) - return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { - target = source; - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { - std::string srcLC = source; - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); - if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") - target = true; - else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") - target = false; - else - return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - } -#ifdef CLARA_CONFIG_OPTIONAL_TYPE - template - inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { - T temp; - auto result = convertInto( source, temp ); - if( result ) - target = std::move(temp); - return result; - } -#endif // CLARA_CONFIG_OPTIONAL_TYPE - - struct NonCopyable { - NonCopyable() = default; - NonCopyable( NonCopyable const & ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable &operator=( NonCopyable const & ) = delete; - NonCopyable &operator=( NonCopyable && ) = delete; - }; - - struct BoundRef : NonCopyable { - virtual ~BoundRef() = default; - virtual auto isContainer() const -> bool { return false; } - virtual auto isFlag() const -> bool { return false; } - }; - struct BoundValueRefBase : BoundRef { - virtual auto setValue( std::string const &arg ) -> ParserResult = 0; - }; - struct BoundFlagRefBase : BoundRef { - virtual auto setFlag( bool flag ) -> ParserResult = 0; - virtual auto isFlag() const -> bool { return true; } - }; - - template - struct BoundValueRef : BoundValueRefBase { - T &m_ref; - - explicit BoundValueRef( T &ref ) : m_ref( ref ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return convertInto( arg, m_ref ); - } - }; - - template - struct BoundValueRef> : BoundValueRefBase { - std::vector &m_ref; - - explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} - - auto isContainer() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - T temp; - auto result = convertInto( arg, temp ); - if( result ) - m_ref.push_back( temp ); - return result; - } - }; - - struct BoundFlagRef : BoundFlagRefBase { - bool &m_ref; - - explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} - - auto setFlag( bool flag ) -> ParserResult override { - m_ref = flag; - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - struct LambdaInvoker { - static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); - - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - return lambda( arg ); - } - }; - - template<> - struct LambdaInvoker { - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - lambda( arg ); - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp{}; - auto result = convertInto( arg, temp ); - return !result - ? result - : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - } - - template - struct BoundLambda : BoundValueRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return invokeLambda::ArgType>( m_lambda, arg ); - } - }; - - template - struct BoundFlagLambda : BoundFlagRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); - - explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setFlag( bool flag ) -> ParserResult override { - return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); - } - }; - - enum class Optionality { Optional, Required }; - - struct Parser; - - class ParserBase { - public: - virtual ~ParserBase() = default; - virtual auto validate() const -> Result { return Result::ok(); } - virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; - virtual auto cardinality() const -> size_t { return 1; } - - auto parse( Args const &args ) const -> InternalParseResult { - return parse( args.exeName(), TokenStream( args ) ); - } - }; - - template - class ComposableParserImpl : public ParserBase { - public: - template - auto operator|( T const &other ) const -> Parser; - - template - auto operator+( T const &other ) const -> Parser; - }; - - // Common code and state for Args and Opts - template - class ParserRefImpl : public ComposableParserImpl { - protected: - Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; - std::string m_hint; - std::string m_description; - - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} - - public: - template - ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint( hint ) - {} - - template - ParserRefImpl( LambdaT const &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint(hint) - {} - - auto operator()( std::string const &description ) -> DerivedT & { - m_description = description; - return static_cast( *this ); - } - - auto optional() -> DerivedT & { - m_optionality = Optionality::Optional; - return static_cast( *this ); - }; - - auto required() -> DerivedT & { - m_optionality = Optionality::Required; - return static_cast( *this ); - }; - - auto isOptional() const -> bool { - return m_optionality == Optionality::Optional; - } - - auto cardinality() const -> size_t override { - if( m_ref->isContainer() ) - return 0; - else - return 1; - } - - auto hint() const -> std::string { return m_hint; } - }; - - class ExeName : public ComposableParserImpl { - std::shared_ptr m_name; - std::shared_ptr m_ref; - - template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { - return std::make_shared>( lambda) ; - } - - public: - ExeName() : m_name( std::make_shared( "" ) ) {} - - explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); - } - - template - explicit ExeName( LambdaT const& lambda ) : ExeName() { - m_ref = std::make_shared>( lambda ); - } - - // The exe name is not parsed out of the normal tokens, but is handled specially - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - } - - auto name() const -> std::string { return *m_name; } - auto set( std::string const& newName ) -> ParserResult { - - auto lastSlash = newName.find_last_of( "\\/" ); - auto filename = ( lastSlash == std::string::npos ) - ? newName - : newName.substr( lastSlash+1 ); - - *m_name = filename; - if( m_ref ) - return m_ref->setValue( filename ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - class Arg : public ParserRefImpl { - public: - using ParserRefImpl::ParserRefImpl; - - auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); - - auto remainingTokens = tokens; - auto const &token = *remainingTokens; - if( token.type != TokenType::Argument ) - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - - assert( !m_ref->isFlag() ); - auto valueRef = static_cast( m_ref.get() ); - - auto result = valueRef->setValue( remainingTokens->token ); - if( !result ) - return InternalParseResult( result ); - else - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - }; - - inline auto normaliseOpt( std::string const &optName ) -> std::string { -#ifdef CATCH_PLATFORM_WINDOWS - if( optName[0] == '/' ) - return "-" + optName.substr( 1 ); - else -#endif - return optName; - } - - class Opt : public ParserRefImpl { - protected: - std::vector m_optNames; - - public: - template - explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} - - explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} - - template - Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - - template - Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - - auto operator[]( std::string const &optName ) -> Opt & { - m_optNames.push_back( optName ); - return *this; - } - - auto getHelpColumns() const -> std::vector { - std::ostringstream oss; - bool first = true; - for( auto const &opt : m_optNames ) { - if (first) - first = false; - else - oss << ", "; - oss << opt; - } - if( !m_hint.empty() ) - oss << " <" << m_hint << ">"; - return { { oss.str(), m_description } }; - } - - auto isMatch( std::string const &optToken ) const -> bool { - auto normalisedToken = normaliseOpt( optToken ); - for( auto const &name : m_optNames ) { - if( normaliseOpt( name ) == normalisedToken ) - return true; - } - return false; - } - - using ParserBase::parse; - - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); - - auto remainingTokens = tokens; - if( remainingTokens && remainingTokens->type == TokenType::Option ) { - auto const &token = *remainingTokens; - if( isMatch(token.token ) ) { - if( m_ref->isFlag() ) { - auto flagRef = static_cast( m_ref.get() ); - auto result = flagRef->setFlag( true ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } else { - auto valueRef = static_cast( m_ref.get() ); - ++remainingTokens; - if( !remainingTokens ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto const &argToken = *remainingTokens; - if( argToken.type != TokenType::Argument ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto result = valueRef->setValue( argToken.token ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - } - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - } - - auto validate() const -> Result override { - if( m_optNames.empty() ) - return Result::logicError( "No options supplied to Opt" ); - for( auto const &name : m_optNames ) { - if( name.empty() ) - return Result::logicError( "Option name cannot be empty" ); -#ifdef CATCH_PLATFORM_WINDOWS - if( name[0] != '-' && name[0] != '/' ) - return Result::logicError( "Option name must begin with '-' or '/'" ); -#else - if( name[0] != '-' ) - return Result::logicError( "Option name must begin with '-'" ); -#endif - } - return ParserRefImpl::validate(); - } - }; - - struct Help : Opt { - Help( bool &showHelpFlag ) - : Opt([&]( bool flag ) { - showHelpFlag = flag; - return ParserResult::ok( ParseResultType::ShortCircuitAll ); - }) - { - static_cast( *this ) - ("display usage information") - ["-?"]["-h"]["--help"] - .optional(); - } - }; - - struct Parser : ParserBase { - - mutable ExeName m_exeName; - std::vector m_options; - std::vector m_args; - - auto operator|=( ExeName const &exeName ) -> Parser & { - m_exeName = exeName; - return *this; - } - - auto operator|=( Arg const &arg ) -> Parser & { - m_args.push_back(arg); - return *this; - } - - auto operator|=( Opt const &opt ) -> Parser & { - m_options.push_back(opt); - return *this; - } - - auto operator|=( Parser const &other ) -> Parser & { - m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); - m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); - return *this; - } - - template - auto operator|( T const &other ) const -> Parser { - return Parser( *this ) |= other; - } - - // Forward deprecated interface with '+' instead of '|' - template - auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } - template - auto operator+( T const &other ) const -> Parser { return operator|( other ); } - - auto getHelpColumns() const -> std::vector { - std::vector cols; - for (auto const &o : m_options) { - auto childCols = o.getHelpColumns(); - cols.insert( cols.end(), childCols.begin(), childCols.end() ); - } - return cols; - } - - void writeToStream( std::ostream &os ) const { - if (!m_exeName.name().empty()) { - os << "usage:\n" << " " << m_exeName.name() << " "; - bool required = true, first = true; - for( auto const &arg : m_args ) { - if (first) - first = false; - else - os << " "; - if( arg.isOptional() && required ) { - os << "["; - required = false; - } - os << "<" << arg.hint() << ">"; - if( arg.cardinality() == 0 ) - os << " ... "; - } - if( !required ) - os << "]"; - if( !m_options.empty() ) - os << " options"; - os << "\n\nwhere options are:" << std::endl; - } - - auto rows = getHelpColumns(); - size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; - size_t optWidth = 0; - for( auto const &cols : rows ) - optWidth = (std::max)(optWidth, cols.left.size() + 2); - - optWidth = (std::min)(optWidth, consoleWidth/2); - - for( auto const &cols : rows ) { - auto row = - TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + - TextFlow::Spacer(4) + - TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); - os << row << std::endl; - } - } - - friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { - parser.writeToStream( os ); - return os; - } - - auto validate() const -> Result override { - for( auto const &opt : m_options ) { - auto result = opt.validate(); - if( !result ) - return result; - } - for( auto const &arg : m_args ) { - auto result = arg.validate(); - if( !result ) - return result; - } - return Result::ok(); - } - - using ParserBase::parse; - - auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { - - struct ParserInfo { - ParserBase const* parser = nullptr; - size_t count = 0; - }; - const size_t totalParsers = m_options.size() + m_args.size(); - assert( totalParsers < 512 ); - // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do - ParserInfo parseInfos[512]; - - { - size_t i = 0; - for (auto const &opt : m_options) parseInfos[i++].parser = &opt; - for (auto const &arg : m_args) parseInfos[i++].parser = &arg; - } - - m_exeName.set( exeName ); - - auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - while( result.value().remainingTokens() ) { - bool tokenParsed = false; - - for( size_t i = 0; i < totalParsers; ++i ) { - auto& parseInfo = parseInfos[i]; - if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { - result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); - if (!result) - return result; - if (result.value().type() != ParseResultType::NoMatch) { - tokenParsed = true; - ++parseInfo.count; - break; - } - } - } - - if( result.value().type() == ParseResultType::ShortCircuitAll ) - return result; - if( !tokenParsed ) - return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); - } - // !TBD Check missing required options - return result; - } - }; - - template - template - auto ComposableParserImpl::operator|( T const &other ) const -> Parser { - return Parser() | static_cast( *this ) | other; - } -} // namespace detail - -// A Combined parser -using detail::Parser; - -// A parser for options -using detail::Opt; - -// A parser for arguments -using detail::Arg; - -// Wrapper for argc, argv from main() -using detail::Args; - -// Specifies the name of the executable -using detail::ExeName; - -// Convenience wrapper for option parser that specifies the help option -using detail::Help; - -// enum of result types from a parse -using detail::ParseResultType; - -// Result type for parser operation -using detail::ParserResult; - -}} // namespace Catch::clara - -// end clara.hpp -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// Restore Clara's value for console width, if present -#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -// end catch_clara.h -namespace Catch { - - clara::Parser makeCommandLineParser( ConfigData& config ); - -} // end namespace Catch - -// end catch_commandline.h -#include -#include - -namespace Catch { - - clara::Parser makeCommandLineParser( ConfigData& config ) { - - using namespace clara; - - auto const setWarning = [&]( std::string const& warning ) { - auto warningSet = [&]() { - if( warning == "NoAssertions" ) - return WarnAbout::NoAssertions; - - if ( warning == "NoTests" ) - return WarnAbout::NoTests; - - return WarnAbout::Nothing; - }(); - - if (warningSet == WarnAbout::Nothing) - return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); - config.warnings = static_cast( config.warnings | warningSet ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const loadTestNamesFromFile = [&]( std::string const& filename ) { - std::ifstream f( filename.c_str() ); - if( !f.is_open() ) - return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); - - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, '#' ) ) { - if( !startsWith( line, '"' ) ) - line = '"' + line + '"'; - config.testsOrTags.push_back( line + ',' ); - } - } - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setTestOrder = [&]( std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setRngSeed = [&]( std::string const& seed ) { - if( seed != "time" ) - return clara::detail::convertInto( seed, config.rngSeed ); - config.rngSeed = static_cast( std::time(nullptr) ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setColourUsage = [&]( std::string const& useColour ) { - auto mode = toLower( useColour ); - - if( mode == "yes" ) - config.useColour = UseColour::Yes; - else if( mode == "no" ) - config.useColour = UseColour::No; - else if( mode == "auto" ) - config.useColour = UseColour::Auto; - else - return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setWaitForKeypress = [&]( std::string const& keypress ) { - auto keypressLc = toLower( keypress ); - if( keypressLc == "start" ) - config.waitForKeypress = WaitForKeypress::BeforeStart; - else if( keypressLc == "exit" ) - config.waitForKeypress = WaitForKeypress::BeforeExit; - else if( keypressLc == "both" ) - config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; - else - return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setVerbosity = [&]( std::string const& verbosity ) { - auto lcVerbosity = toLower( verbosity ); - if( lcVerbosity == "quiet" ) - config.verbosity = Verbosity::Quiet; - else if( lcVerbosity == "normal" ) - config.verbosity = Verbosity::Normal; - else if( lcVerbosity == "high" ) - config.verbosity = Verbosity::High; - else - return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - - auto cli - = ExeName( config.processName ) - | Help( config.showHelp ) - | Opt( config.listTests ) - ["-l"]["--list-tests"] - ( "list all/matching test cases" ) - | Opt( config.listTags ) - ["-t"]["--list-tags"] - ( "list all/matching tags" ) - | Opt( config.showSuccessfulTests ) - ["-s"]["--success"] - ( "include successful tests in output" ) - | Opt( config.shouldDebugBreak ) - ["-b"]["--break"] - ( "break into debugger on failure" ) - | Opt( config.noThrow ) - ["-e"]["--nothrow"] - ( "skip exception tests" ) - | Opt( config.showInvisibles ) - ["-i"]["--invisibles"] - ( "show invisibles (tabs, newlines)" ) - | Opt( config.outputFilename, "filename" ) - ["-o"]["--out"] - ( "output filename" ) - | Opt( config.reporterName, "name" ) - ["-r"]["--reporter"] - ( "reporter to use (defaults to console)" ) - | Opt( config.name, "name" ) - ["-n"]["--name"] - ( "suite name" ) - | Opt( [&]( bool ){ config.abortAfter = 1; } ) - ["-a"]["--abort"] - ( "abort at first failure" ) - | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) - ["-x"]["--abortx"] - ( "abort after x failures" ) - | Opt( setWarning, "warning name" ) - ["-w"]["--warn"] - ( "enable warnings" ) - | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) - ["-d"]["--durations"] - ( "show test durations" ) - | Opt( loadTestNamesFromFile, "filename" ) - ["-f"]["--input-file"] - ( "load test names to run from a file" ) - | Opt( config.filenamesAsTags ) - ["-#"]["--filenames-as-tags"] - ( "adds a tag for the filename" ) - | Opt( config.sectionsToRun, "section name" ) - ["-c"]["--section"] - ( "specify section to run" ) - | Opt( setVerbosity, "quiet|normal|high" ) - ["-v"]["--verbosity"] - ( "set output verbosity" ) - | Opt( config.listTestNamesOnly ) - ["--list-test-names-only"] - ( "list all/matching test cases names only" ) - | Opt( config.listReporters ) - ["--list-reporters"] - ( "list all reporters" ) - | Opt( setTestOrder, "decl|lex|rand" ) - ["--order"] - ( "test case order (defaults to decl)" ) - | Opt( setRngSeed, "'time'|number" ) - ["--rng-seed"] - ( "set a specific seed for random numbers" ) - | Opt( setColourUsage, "yes|no" ) - ["--use-colour"] - ( "should output be colourised" ) - | Opt( config.libIdentify ) - ["--libidentify"] - ( "report name and version according to libidentify standard" ) - | Opt( setWaitForKeypress, "start|exit|both" ) - ["--wait-for-keypress"] - ( "waits for a keypress before exiting" ) - | Opt( config.benchmarkResolutionMultiple, "multiplier" ) - ["--benchmark-resolution-multiple"] - ( "multiple of clock resolution to run benchmarks" ) - - | Arg( config.testsOrTags, "test name|pattern|tags" ) - ( "which test or tests to use" ); - - return cli; - } - -} // end namespace Catch -// end catch_commandline.cpp -// start catch_common.cpp - -#include -#include - -namespace Catch { - - bool SourceLineInfo::empty() const noexcept { - return file[0] == '\0'; - } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { - return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); - } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { - // We can assume that the same file will usually have the same pointer. - // Thus, if the pointers are the same, there is no point in calling the strcmp - return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); - } - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << '(' << info.line << ')'; -#else - os << info.file << ':' << info.line; -#endif - return os; - } - - std::string StreamEndStop::operator+() const { - return std::string(); - } - - NonCopyable::NonCopyable() = default; - NonCopyable::~NonCopyable() = default; - -} -// end catch_common.cpp -// start catch_config.cpp - -namespace Catch { - - Config::Config( ConfigData const& data ) - : m_data( data ), - m_stream( openStream() ) - { - TestSpecParser parser(ITagAliasRegistry::get()); - if (data.testsOrTags.empty()) { - parser.parse("~[.]"); // All not hidden tests - } - else { - m_hasTestFilters = true; - for( auto const& testOrTags : data.testsOrTags ) - parser.parse( testOrTags ); - } - m_testSpec = parser.testSpec(); - } - - std::string const& Config::getFilename() const { - return m_data.outputFilename ; - } - - bool Config::listTests() const { return m_data.listTests; } - bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool Config::listTags() const { return m_data.listTags; } - bool Config::listReporters() const { return m_data.listReporters; } - - std::string Config::getProcessName() const { return m_data.processName; } - std::string const& Config::getReporterName() const { return m_data.reporterName; } - - std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } - std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } - - TestSpec const& Config::testSpec() const { return m_testSpec; } - bool Config::hasTestFilters() const { return m_hasTestFilters; } - - bool Config::showHelp() const { return m_data.showHelp; } - - // IConfig interface - bool Config::allowThrows() const { return !m_data.noThrow; } - std::ostream& Config::stream() const { return m_stream->stream(); } - std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } - bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } - ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } - RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } - unsigned int Config::rngSeed() const { return m_data.rngSeed; } - int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } - UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } - bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } - int Config::abortAfter() const { return m_data.abortAfter; } - bool Config::showInvisibles() const { return m_data.showInvisibles; } - Verbosity Config::verbosity() const { return m_data.verbosity; } - - IStream const* Config::openStream() { - return Catch::makeStream(m_data.outputFilename); - } - -} // end namespace Catch -// end catch_config.cpp -// start catch_console_colour.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -// start catch_errno_guard.h - -namespace Catch { - - class ErrnoGuard { - public: - ErrnoGuard(); - ~ErrnoGuard(); - private: - int m_oldErrno; - }; - -} - -// end catch_errno_guard.h -#include - -namespace Catch { - namespace { - - struct IColourImpl { - virtual ~IColourImpl() = default; - virtual void use( Colour::Code _colourCode ) = 0; - }; - - struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} - - static IColourImpl* instance() { - static NoColourImpl s_instance; - return &s_instance; - } - }; - - } // anon namespace -} // namespace Catch - -#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) -# ifdef CATCH_PLATFORM_WINDOWS -# define CATCH_CONFIG_COLOUR_WINDOWS -# else -# define CATCH_CONFIG_COLOUR_ANSI -# endif -#endif - -#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// - -namespace Catch { -namespace { - - class Win32ColourImpl : public IColourImpl { - public: - Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) - { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); - originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); - } - - virtual void use( Colour::Code _colourCode ) override { - switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalForegroundAttributes ); - case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Red: return setTextAttribute( FOREGROUND_RED ); - case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); - case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); - case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); - case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Grey: return setTextAttribute( 0 ); - - case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); - case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); - case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); - case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); - - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - - default: - CATCH_ERROR( "Unknown colour requested" ); - } - } - - private: - void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); - } - HANDLE stdoutHandle; - WORD originalForegroundAttributes; - WORD originalBackgroundAttributes; - }; - - IColourImpl* platformColourInstance() { - static Win32ColourImpl s_instance; - - IConfigPtr config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = UseColour::Yes; - return colourMode == UseColour::Yes - ? &s_instance - : NoColourImpl::instance(); - } - -} // end anon namespace -} // end namespace Catch - -#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// - -#include - -namespace Catch { -namespace { - - // use POSIX/ ANSI console terminal codes - // Thanks to Adam Strzelecki for original contribution - // (http://github.com/nanoant) - // https://github.com/philsquared/Catch/pull/131 - class PosixColourImpl : public IColourImpl { - public: - virtual void use( Colour::Code _colourCode ) override { - switch( _colourCode ) { - case Colour::None: - case Colour::White: return setColour( "[0m" ); - case Colour::Red: return setColour( "[0;31m" ); - case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0;34m" ); - case Colour::Cyan: return setColour( "[0;36m" ); - case Colour::Yellow: return setColour( "[0;33m" ); - case Colour::Grey: return setColour( "[1;30m" ); - - case Colour::LightGrey: return setColour( "[0;37m" ); - case Colour::BrightRed: return setColour( "[1;31m" ); - case Colour::BrightGreen: return setColour( "[1;32m" ); - case Colour::BrightWhite: return setColour( "[1;37m" ); - case Colour::BrightYellow: return setColour( "[1;33m" ); - - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); - } - } - static IColourImpl* instance() { - static PosixColourImpl s_instance; - return &s_instance; - } - - private: - void setColour( const char* _escapeCode ) { - Catch::cout() << '\033' << _escapeCode; - } - }; - - bool useColourOnPlatform() { - return -#ifdef CATCH_PLATFORM_MAC - !isDebuggerActive() && -#endif -#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) - isatty(STDOUT_FILENO) -#else - false -#endif - ; - } - IColourImpl* platformColourInstance() { - ErrnoGuard guard; - IConfigPtr config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = useColourOnPlatform() - ? UseColour::Yes - : UseColour::No; - return colourMode == UseColour::Yes - ? PosixColourImpl::instance() - : NoColourImpl::instance(); - } - -} // end anon namespace -} // end namespace Catch - -#else // not Windows or ANSI /////////////////////////////////////////////// - -namespace Catch { - - static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } - -} // end namespace Catch - -#endif // Windows/ ANSI/ None - -namespace Catch { - - Colour::Colour( Code _colourCode ) { use( _colourCode ); } - Colour::Colour( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - } - Colour& Colour::operator=( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - return *this; - } - - Colour::~Colour(){ if( !m_moved ) use( None ); } - - void Colour::use( Code _colourCode ) { - static IColourImpl* impl = platformColourInstance(); - impl->use( _colourCode ); - } - - std::ostream& operator << ( std::ostream& os, Colour const& ) { - return os; - } - -} // end namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -// end catch_console_colour.cpp -// start catch_context.cpp - -namespace Catch { - - class Context : public IMutableContext, NonCopyable { - - public: // IContext - virtual IResultCapture* getResultCapture() override { - return m_resultCapture; - } - virtual IRunner* getRunner() override { - return m_runner; - } - - virtual IConfigPtr const& getConfig() const override { - return m_config; - } - - virtual ~Context() override; - - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) override { - m_runner = runner; - } - virtual void setConfig( IConfigPtr const& config ) override { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IConfigPtr m_config; - IRunner* m_runner = nullptr; - IResultCapture* m_resultCapture = nullptr; - }; - - IMutableContext *IMutableContext::currentContext = nullptr; - - void IMutableContext::createContext() - { - currentContext = new Context(); - } - - void cleanUpContext() { - delete IMutableContext::currentContext; - IMutableContext::currentContext = nullptr; - } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; -} -// end catch_context.cpp -// start catch_debug_console.cpp - -// start catch_debug_console.h - -#include - -namespace Catch { - void writeToDebugConsole( std::string const& text ); -} - -// end catch_debug_console.h -#ifdef CATCH_PLATFORM_WINDOWS - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } - -#else - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } - } - -#endif // Platform -// end catch_debug_console.cpp -// start catch_debugger.cpp - -#ifdef CATCH_PLATFORM_MAC - -# include -# include -# include -# include -# include -# include -# include - -namespace Catch { - - // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html - - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive(){ - - int mib[4]; - struct kinfo_proc info; - std::size_t size; - - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. - - info.kp_proc.p_flag = 0; - - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - // Call sysctl. - - size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { - Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; - return false; - } - - // We're being debugged if the P_TRACED flag is set. - - return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); - } - } // namespace Catch - -#elif defined(CATCH_PLATFORM_LINUX) - #include - #include - - namespace Catch{ - // The standard POSIX way of detecting a debugger is to attempt to - // ptrace() the process, but this needs to be done from a child and not - // this process itself to still allow attaching to this process later - // if wanted, so is rather heavy. Under Linux we have the PID of the - // "debugger" (which doesn't need to be gdb, of course, it could also - // be strace, for example) in /proc/$PID/status, so just get it from - // there instead. - bool isDebuggerActive(){ - // Libstdc++ has a bug, where std::ifstream sets errno to 0 - // This way our users can properly assert over errno values - ErrnoGuard guard; - std::ifstream in("/proc/self/status"); - for( std::string line; std::getline(in, line); ) { - static const int PREFIX_LEN = 11; - if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { - // We're traced if the PID is not 0 and no other PID starts - // with 0 digit, so it's enough to check for just a single - // character. - return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; - } - } - - return false; - } - } // namespace Catch -#elif defined(_MSC_VER) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#else - namespace Catch { - bool isDebuggerActive() { return false; } - } -#endif // Platform -// end catch_debugger.cpp -// start catch_decomposer.cpp - -namespace Catch { - - ITransientExpression::~ITransientExpression() = default; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { - if( lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ) - os << lhs << " " << op << " " << rhs; - else - os << lhs << "\n" << op << "\n" << rhs; - } -} -// end catch_decomposer.cpp -// start catch_enforce.cpp - -namespace Catch { -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) - [[noreturn]] - void throw_exception(std::exception const& e) { - Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" - << "The message was: " << e.what() << '\n'; - std::terminate(); - } -#endif -} // namespace Catch; -// end catch_enforce.cpp -// start catch_errno_guard.cpp - -#include - -namespace Catch { - ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} - ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } -} -// end catch_errno_guard.cpp -// start catch_exception_translator_registry.cpp - -// start catch_exception_translator_registry.h - -#include -#include -#include - -namespace Catch { - - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry(); - virtual void registerTranslator( const IExceptionTranslator* translator ); - virtual std::string translateActiveException() const override; - std::string tryTranslators() const; - - private: - std::vector> m_translators; - }; -} - -// end catch_exception_translator_registry.h -#ifdef __OBJC__ -#import "Foundation/Foundation.h" -#endif - -namespace Catch { - - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { - } - - void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( std::unique_ptr( translator ) ); - } - -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - std::string ExceptionTranslatorRegistry::translateActiveException() const { - try { -#ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - return tryTranslators(); - } - @catch (NSException *exception) { - return Catch::Detail::stringify( [exception description] ); - } -#else - // Compiling a mixed mode project with MSVC means that CLR - // exceptions will be caught in (...) as well. However, these - // do not fill-in std::current_exception and thus lead to crash - // when attempting rethrow. - // /EHa switch also causes structured exceptions to be caught - // here, but they fill-in current_exception properly, so - // at worst the output should be a little weird, instead of - // causing a crash. - if (std::current_exception() == nullptr) { - return "Non C++ exception. Possibly a CLR exception."; - } - return tryTranslators(); -#endif - } - catch( TestFailureException& ) { - std::rethrow_exception(std::current_exception()); - } - catch( std::exception& ex ) { - return ex.what(); - } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return "Unknown exception"; - } - } - -#else // ^^ Exceptions are enabled // Exceptions are disabled vv - std::string ExceptionTranslatorRegistry::translateActiveException() const { - CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); - } -#endif - - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if( m_translators.empty() ) - std::rethrow_exception(std::current_exception()); - else - return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); - } -} -// end catch_exception_translator_registry.cpp -// start catch_fatal_condition.cpp - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - -#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) - -namespace { - // Report the error condition - void reportFatal( char const * const message ) { - Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); - } -} - -#endif // signals/SEH handling - -#if defined( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - struct SignalDefs { DWORD id; const char* name; }; - - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - static SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, - }; - - LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { - for (auto const& def : signalDefs) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { - reportFatal(def.name); - } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; - } - - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = nullptr; - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - } - - void FatalConditionHandler::reset() { - if (isSet) { - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = nullptr; - isSet = false; - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - -bool FatalConditionHandler::isSet = false; -ULONG FatalConditionHandler::guaranteeSize = 0; -PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; - -} // namespace Catch - -#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) - -namespace Catch { - - struct SignalDefs { - int id; - const char* name; - }; - - // 32kb for the alternate stack seems to be sufficient. However, this value - // is experimentally determined, so that's not guaranteed. - constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; - - static SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; - - void FatalConditionHandler::handleSignal( int sig ) { - char const * name = ""; - for (auto const& def : signalDefs) { - if (sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise( sig ); - } - - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = sigStackSize; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = { }; - - sa.sa_handler = handleSignal; - sa.sa_flags = SA_ONSTACK; - for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - - void FatalConditionHandler::reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } - } - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[sigStackSize] = {}; - -} // namespace Catch - -#else - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -#endif // signals/SEH handling - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif -// end catch_fatal_condition.cpp -// start catch_generators.cpp - -// start catch_random_number_generator.h - -#include -#include - -namespace Catch { - - struct IConfig; - - std::mt19937& rng(); - void seedRng( IConfig const& config ); - unsigned int rngSeed(); - -} - -// end catch_random_number_generator.h -#include -#include - -namespace Catch { - -IGeneratorTracker::~IGeneratorTracker() {} - -namespace Generators { - - GeneratorBase::~GeneratorBase() {} - - std::vector randomiseIndices( size_t selectionSize, size_t sourceSize ) { - - assert( selectionSize <= sourceSize ); - std::vector indices; - indices.reserve( selectionSize ); - std::uniform_int_distribution uid( 0, sourceSize-1 ); - - std::set seen; - // !TBD: improve this algorithm - while( indices.size() < selectionSize ) { - auto index = uid( rng() ); - if( seen.insert( index ).second ) - indices.push_back( index ); - } - return indices; - } - - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { - return getResultCapture().acquireGeneratorTracker( lineInfo ); - } - - template<> - auto all() -> Generator { - return range( std::numeric_limits::min(), std::numeric_limits::max() ); - } - -} // namespace Generators -} // namespace Catch -// end catch_generators.cpp -// start catch_interfaces_capture.cpp - -namespace Catch { - IResultCapture::~IResultCapture() = default; -} -// end catch_interfaces_capture.cpp -// start catch_interfaces_config.cpp - -namespace Catch { - IConfig::~IConfig() = default; -} -// end catch_interfaces_config.cpp -// start catch_interfaces_exception.cpp - -namespace Catch { - IExceptionTranslator::~IExceptionTranslator() = default; - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; -} -// end catch_interfaces_exception.cpp -// start catch_interfaces_registry_hub.cpp - -namespace Catch { - IRegistryHub::~IRegistryHub() = default; - IMutableRegistryHub::~IMutableRegistryHub() = default; -} -// end catch_interfaces_registry_hub.cpp -// start catch_interfaces_reporter.cpp - -// start catch_reporter_listening.h - -namespace Catch { - - class ListeningReporter : public IStreamingReporter { - using Reporters = std::vector; - Reporters m_listeners; - IStreamingReporterPtr m_reporter = nullptr; - ReporterPreferences m_preferences; - - public: - ListeningReporter(); - - void addListener( IStreamingReporterPtr&& listener ); - void addReporter( IStreamingReporterPtr&& reporter ); - - public: // IStreamingReporter - - ReporterPreferences getPreferences() const override; - - void noMatchingTestCases( std::string const& spec ) override; - - static std::set getSupportedVerbosities(); - - void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; - void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; - - void testRunStarting( TestRunInfo const& testRunInfo ) override; - void testGroupStarting( GroupInfo const& groupInfo ) override; - void testCaseStarting( TestCaseInfo const& testInfo ) override; - void sectionStarting( SectionInfo const& sectionInfo ) override; - void assertionStarting( AssertionInfo const& assertionInfo ) override; - - // The return value indicates if the messages buffer should be cleared: - bool assertionEnded( AssertionStats const& assertionStats ) override; - void sectionEnded( SectionStats const& sectionStats ) override; - void testCaseEnded( TestCaseStats const& testCaseStats ) override; - void testGroupEnded( TestGroupStats const& testGroupStats ) override; - void testRunEnded( TestRunStats const& testRunStats ) override; - - void skipTest( TestCaseInfo const& testInfo ) override; - bool isMulti() const override; - - }; - -} // end namespace Catch - -// end catch_reporter_listening.h -namespace Catch { - - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - - std::ostream& ReporterConfig::stream() const { return *m_stream; } - IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } - - TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} - - GroupInfo::GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} - - AssertionStats::AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); - - infoMessages.push_back( builder.m_info ); - } - } - - AssertionStats::~AssertionStats() = default; - - SectionStats::SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} - - SectionStats::~SectionStats() = default; - - TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} - - TestCaseStats::~TestCaseStats() = default; - - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} - - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} - - TestGroupStats::~TestGroupStats() = default; - - TestRunStats::TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - - TestRunStats::~TestRunStats() = default; - - void IStreamingReporter::fatalErrorEncountered( StringRef ) {} - bool IStreamingReporter::isMulti() const { return false; } - - IReporterFactory::~IReporterFactory() = default; - IReporterRegistry::~IReporterRegistry() = default; - -} // end namespace Catch -// end catch_interfaces_reporter.cpp -// start catch_interfaces_runner.cpp - -namespace Catch { - IRunner::~IRunner() = default; -} -// end catch_interfaces_runner.cpp -// start catch_interfaces_testcase.cpp - -namespace Catch { - ITestInvoker::~ITestInvoker() = default; - ITestCaseRegistry::~ITestCaseRegistry() = default; -} -// end catch_interfaces_testcase.cpp -// start catch_leak_detector.cpp - -#ifdef CATCH_CONFIG_WINDOWS_CRTDBG -#include - -namespace Catch { - - LeakDetector::LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } -} - -#else - - Catch::LeakDetector::LeakDetector() {} - -#endif -// end catch_leak_detector.cpp -// start catch_list.cpp - -// start catch_list.h - -#include - -namespace Catch { - - std::size_t listTests( Config const& config ); - - std::size_t listTestsNamesOnly( Config const& config ); - - struct TagInfo { - void add( std::string const& spelling ); - std::string all() const; - - std::set spellings; - std::size_t count = 0; - }; - - std::size_t listTags( Config const& config ); - - std::size_t listReporters( Config const& /*config*/ ); - - Option list( Config const& config ); - -} // end namespace Catch - -// end catch_list.h -// start catch_text.h - -namespace Catch { - using namespace clara::TextFlow; -} - -// end catch_text.h -#include -#include -#include - -namespace Catch { - - std::size_t listTests( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.hasTestFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - } - - auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); - - Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; - if( config.verbosity() >= Verbosity::High ) { - Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; - std::string description = testCaseInfo.description; - if( description.empty() ) - description = "(NO DESCRIPTION)"; - Catch::cout() << Column( description ).indent(4) << std::endl; - } - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; - } - - if( !config.hasTestFilters() ) - Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; - else - Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; - return matchedTestCases.size(); - } - - std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - std::size_t matchedTests = 0; - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - matchedTests++; - if( startsWith( testCaseInfo.name, '#' ) ) - Catch::cout() << '"' << testCaseInfo.name << '"'; - else - Catch::cout() << testCaseInfo.name; - if ( config.verbosity() >= Verbosity::High ) - Catch::cout() << "\t@" << testCaseInfo.lineInfo; - Catch::cout() << std::endl; - } - return matchedTests; - } - - void TagInfo::add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); - } - - std::string TagInfo::all() const { - std::string out; - for( auto const& spelling : spellings ) - out += "[" + spelling + "]"; - return out; - } - - std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.hasTestFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - } - - std::map tagCounts; - - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCase : matchedTestCases ) { - for( auto const& tagName : testCase.getTestCaseInfo().tags ) { - std::string lcaseTagName = toLower( tagName ); - auto countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); - } - } - - for( auto const& tagCount : tagCounts ) { - ReusableStringStream rss; - rss << " " << std::setw(2) << tagCount.second.count << " "; - auto str = rss.str(); - auto wrapper = Column( tagCount.second.all() ) - .initialIndent( 0 ) - .indent( str.size() ) - .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); - Catch::cout() << str << wrapper << '\n'; - } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; - return tagCounts.size(); - } - - std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - std::size_t maxNameLen = 0; - for( auto const& factoryKvp : factories ) - maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); - - for( auto const& factoryKvp : factories ) { - Catch::cout() - << Column( factoryKvp.first + ":" ) - .indent(2) - .width( 5+maxNameLen ) - + Column( factoryKvp.second->getDescription() ) - .initialIndent(0) - .indent(2) - .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) - << "\n"; - } - Catch::cout() << std::endl; - return factories.size(); - } - - Option list( Config const& config ) { - Option listedCount; - if( config.listTests() ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; - } - -} // end namespace Catch -// end catch_list.cpp -// start catch_matchers.cpp - -namespace Catch { -namespace Matchers { - namespace Impl { - - std::string MatcherUntypedBase::toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; - } - - MatcherUntypedBase::~MatcherUntypedBase() = default; - - } // namespace Impl -} // namespace Matchers - -using namespace Matchers; -using Matchers::Impl::MatcherBase; - -} // namespace Catch -// end catch_matchers.cpp -// start catch_matchers_floating.cpp - -// start catch_to_string.hpp - -#include - -namespace Catch { - template - std::string to_string(T const& t) { -#if defined(CATCH_CONFIG_CPP11_TO_STRING) - return std::to_string(t); -#else - ReusableStringStream rss; - rss << t; - return rss.str(); -#endif - } -} // end namespace Catch - -// end catch_to_string.hpp -#include -#include -#include - -namespace Catch { -namespace Matchers { -namespace Floating { -enum class FloatingPointKind : uint8_t { - Float, - Double -}; -} -} -} - -namespace { - -template -struct Converter; - -template <> -struct Converter { - static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); - Converter(float f) { - std::memcpy(&i, &f, sizeof(f)); - } - int32_t i; -}; - -template <> -struct Converter { - static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); - Converter(double d) { - std::memcpy(&i, &d, sizeof(d)); - } - int64_t i; -}; - -template -auto convert(T t) -> Converter { - return Converter(t); -} - -template -bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { - // Comparison with NaN should always be false. - // This way we can rule it out before getting into the ugly details - if (std::isnan(lhs) || std::isnan(rhs)) { - return false; - } - - auto lc = convert(lhs); - auto rc = convert(rhs); - - if ((lc.i < 0) != (rc.i < 0)) { - // Potentially we can have +0 and -0 - return lhs == rhs; - } - - auto ulpDiff = std::abs(lc.i - rc.i); - return ulpDiff <= maxUlpDiff; -} - -} - -namespace Catch { -namespace Matchers { -namespace Floating { - WithinAbsMatcher::WithinAbsMatcher(double target, double margin) - :m_target{ target }, m_margin{ margin } { - CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' - << " Margin has to be non-negative."); - } - - // Performs equivalent check of std::fabs(lhs - rhs) <= margin - // But without the subtraction to allow for INFINITY in comparison - bool WithinAbsMatcher::match(double const& matchee) const { - return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); - } - - std::string WithinAbsMatcher::describe() const { - return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); - } - - WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) - :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { - CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.' - << " ULPs have to be non-negative."); - } - -#if defined(__clang__) -#pragma clang diagnostic push -// Clang <3.5 reports on the default branch in the switch below -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - - bool WithinUlpsMatcher::match(double const& matchee) const { - switch (m_type) { - case FloatingPointKind::Float: - return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); - case FloatingPointKind::Double: - return almostEqualUlps(matchee, m_target, m_ulps); - default: - CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); - } - } - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - - std::string WithinUlpsMatcher::describe() const { - return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); - } - -}// namespace Floating - -Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { - return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); -} - -Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { - return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); -} - -Floating::WithinAbsMatcher WithinAbs(double target, double margin) { - return Floating::WithinAbsMatcher(target, margin); -} - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_floating.cpp -// start catch_matchers_generic.cpp - -std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { - if (desc.empty()) { - return "matches undescribed predicate"; - } else { - return "matches predicate: \"" + desc + '"'; - } -} -// end catch_matchers_generic.cpp -// start catch_matchers_string.cpp - -#include - -namespace Catch { -namespace Matchers { - - namespace StdString { - - CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_str( adjustString( str ) ) - {} - std::string CasedString::adjustString( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No - ? toLower( str ) - : str; - } - std::string CasedString::caseSensitivitySuffix() const { - return m_caseSensitivity == CaseSensitive::No - ? " (case insensitive)" - : std::string(); - } - - StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) - : m_comparator( comparator ), - m_operation( operation ) { - } - - std::string StringMatcherBase::describe() const { - std::string description; - description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + - m_comparator.caseSensitivitySuffix().size()); - description += m_operation; - description += ": \""; - description += m_comparator.m_str; - description += "\""; - description += m_comparator.caseSensitivitySuffix(); - return description; - } - - EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} - - bool EqualsMatcher::match( std::string const& source ) const { - return m_comparator.adjustString( source ) == m_comparator.m_str; - } - - ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} - - bool ContainsMatcher::match( std::string const& source ) const { - return contains( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} - - bool StartsWithMatcher::match( std::string const& source ) const { - return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} - - bool EndsWithMatcher::match( std::string const& source ) const { - return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} - - bool RegexMatcher::match(std::string const& matchee) const { - auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway - if (m_caseSensitivity == CaseSensitive::Choice::No) { - flags |= std::regex::icase; - } - auto reg = std::regex(m_regex, flags); - return std::regex_match(matchee, reg); - } - - std::string RegexMatcher::describe() const { - return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); - } - - } // namespace StdString - - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } - - StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { - return StdString::RegexMatcher(regex, caseSensitivity); - } - -} // namespace Matchers -} // namespace Catch -// end catch_matchers_string.cpp -// start catch_message.cpp - -// start catch_uncaught_exceptions.h - -namespace Catch { - bool uncaught_exceptions(); -} // end namespace Catch - -// end catch_uncaught_exceptions.h -#include - -namespace Catch { - - MessageInfo::MessageInfo( StringRef const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} - - bool MessageInfo::operator==( MessageInfo const& other ) const { - return sequence == other.sequence; - } - - bool MessageInfo::operator<( MessageInfo const& other ) const { - return sequence < other.sequence; - } - - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - - //////////////////////////////////////////////////////////////////////////// - - Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - :m_info(macroName, lineInfo, type) {} - - //////////////////////////////////////////////////////////////////////////// - - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } - - ScopedMessage::~ScopedMessage() { - if ( !uncaught_exceptions() ){ - getResultCapture().popScopedMessage(m_info); - } - } - - Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { - auto start = std::string::npos; - for( size_t pos = 0; pos <= names.size(); ++pos ) { - char c = names[pos]; - if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) { - if( start != std::string::npos ) { - m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) ); - m_messages.back().message = names.substr( start, pos-start) + " := "; - start = std::string::npos; - } - } - else if( c != '[' && c != ']' && start == std::string::npos ) - start = pos; - } - } - Capturer::~Capturer() { - if ( !uncaught_exceptions() ){ - assert( m_captured == m_messages.size() ); - for( size_t i = 0; i < m_captured; ++i ) - m_resultCapture.popScopedMessage( m_messages[i] ); - } - } - - void Capturer::captureValue( size_t index, StringRef value ) { - assert( index < m_messages.size() ); - m_messages[index].message += value; - m_resultCapture.pushScopedMessage( m_messages[index] ); - m_captured++; - } - -} // end namespace Catch -// end catch_message.cpp -// start catch_output_redirect.cpp - -// start catch_output_redirect.h -#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H -#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H - -#include -#include -#include - -namespace Catch { - - class RedirectedStream { - std::ostream& m_originalStream; - std::ostream& m_redirectionStream; - std::streambuf* m_prevBuf; - - public: - RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); - ~RedirectedStream(); - }; - - class RedirectedStdOut { - ReusableStringStream m_rss; - RedirectedStream m_cout; - public: - RedirectedStdOut(); - auto str() const -> std::string; - }; - - // StdErr has two constituent streams in C++, std::cerr and std::clog - // This means that we need to redirect 2 streams into 1 to keep proper - // order of writes - class RedirectedStdErr { - ReusableStringStream m_rss; - RedirectedStream m_cerr; - RedirectedStream m_clog; - public: - RedirectedStdErr(); - auto str() const -> std::string; - }; - -#if defined(CATCH_CONFIG_NEW_CAPTURE) - - // Windows's implementation of std::tmpfile is terrible (it tries - // to create a file inside system folder, thus requiring elevated - // privileges for the binary), so we have to use tmpnam(_s) and - // create the file ourselves there. - class TempFile { - public: - TempFile(TempFile const&) = delete; - TempFile& operator=(TempFile const&) = delete; - TempFile(TempFile&&) = delete; - TempFile& operator=(TempFile&&) = delete; - - TempFile(); - ~TempFile(); - - std::FILE* getFile(); - std::string getContents(); - - private: - std::FILE* m_file = nullptr; - #if defined(_MSC_VER) - char m_buffer[L_tmpnam] = { 0 }; - #endif - }; - - class OutputRedirect { - public: - OutputRedirect(OutputRedirect const&) = delete; - OutputRedirect& operator=(OutputRedirect const&) = delete; - OutputRedirect(OutputRedirect&&) = delete; - OutputRedirect& operator=(OutputRedirect&&) = delete; - - OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); - ~OutputRedirect(); - - private: - int m_originalStdout = -1; - int m_originalStderr = -1; - TempFile m_stdoutFile; - TempFile m_stderrFile; - std::string& m_stdoutDest; - std::string& m_stderrDest; - }; - -#endif - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H -// end catch_output_redirect.h -#include -#include -#include -#include -#include - -#if defined(CATCH_CONFIG_NEW_CAPTURE) - #if defined(_MSC_VER) - #include //_dup and _dup2 - #define dup _dup - #define dup2 _dup2 - #define fileno _fileno - #else - #include // dup and dup2 - #endif -#endif - -namespace Catch { - - RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) - : m_originalStream( originalStream ), - m_redirectionStream( redirectionStream ), - m_prevBuf( m_originalStream.rdbuf() ) - { - m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); - } - - RedirectedStream::~RedirectedStream() { - m_originalStream.rdbuf( m_prevBuf ); - } - - RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} - auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } - - RedirectedStdErr::RedirectedStdErr() - : m_cerr( Catch::cerr(), m_rss.get() ), - m_clog( Catch::clog(), m_rss.get() ) - {} - auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } - -#if defined(CATCH_CONFIG_NEW_CAPTURE) - -#if defined(_MSC_VER) - TempFile::TempFile() { - if (tmpnam_s(m_buffer)) { - CATCH_RUNTIME_ERROR("Could not get a temp filename"); - } - if (fopen_s(&m_file, m_buffer, "w")) { - char buffer[100]; - if (strerror_s(buffer, errno)) { - CATCH_RUNTIME_ERROR("Could not translate errno to a string"); - } - CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer); - } - } -#else - TempFile::TempFile() { - m_file = std::tmpfile(); - if (!m_file) { - CATCH_RUNTIME_ERROR("Could not create a temp file."); - } - } - -#endif - - TempFile::~TempFile() { - // TBD: What to do about errors here? - std::fclose(m_file); - // We manually create the file on Windows only, on Linux - // it will be autodeleted -#if defined(_MSC_VER) - std::remove(m_buffer); -#endif - } - - FILE* TempFile::getFile() { - return m_file; - } - - std::string TempFile::getContents() { - std::stringstream sstr; - char buffer[100] = {}; - std::rewind(m_file); - while (std::fgets(buffer, sizeof(buffer), m_file)) { - sstr << buffer; - } - return sstr.str(); - } - - OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : - m_originalStdout(dup(1)), - m_originalStderr(dup(2)), - m_stdoutDest(stdout_dest), - m_stderrDest(stderr_dest) { - dup2(fileno(m_stdoutFile.getFile()), 1); - dup2(fileno(m_stderrFile.getFile()), 2); - } - - OutputRedirect::~OutputRedirect() { - Catch::cout() << std::flush; - fflush(stdout); - // Since we support overriding these streams, we flush cerr - // even though std::cerr is unbuffered - Catch::cerr() << std::flush; - Catch::clog() << std::flush; - fflush(stderr); - - dup2(m_originalStdout, 1); - dup2(m_originalStderr, 2); - - m_stdoutDest += m_stdoutFile.getContents(); - m_stderrDest += m_stderrFile.getContents(); - } - -#endif // CATCH_CONFIG_NEW_CAPTURE - -} // namespace Catch - -#if defined(CATCH_CONFIG_NEW_CAPTURE) - #if defined(_MSC_VER) - #undef dup - #undef dup2 - #undef fileno - #endif -#endif -// end catch_output_redirect.cpp -// start catch_random_number_generator.cpp - -namespace Catch { - - std::mt19937& rng() { - static std::mt19937 s_rng; - return s_rng; - } - - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) { - std::srand( config.rngSeed() ); - rng().seed( config.rngSeed() ); - } - } - - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); - } -} -// end catch_random_number_generator.cpp -// start catch_registry_hub.cpp - -// start catch_test_case_registry_impl.h - -#include -#include -#include -#include - -namespace Catch { - - class TestCase; - struct IConfig; - - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - - void enforceNoDuplicateTestCases( std::vector const& functions ); - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - - class TestRegistry : public ITestCaseRegistry { - public: - virtual ~TestRegistry() = default; - - virtual void registerTest( TestCase const& testCase ); - - std::vector const& getAllTests() const override; - std::vector const& getAllTestsSorted( IConfig const& config ) const override; - - private: - std::vector m_functions; - mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; - mutable std::vector m_sortedFunctions; - std::size_t m_unnamedCount = 0; - std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised - }; - - /////////////////////////////////////////////////////////////////////////// - - class TestInvokerAsFunction : public ITestInvoker { - void(*m_testAsFunction)(); - public: - TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; - - void invoke() const override; - }; - - std::string extractClassName( StringRef const& classOrQualifiedMethodName ); - - /////////////////////////////////////////////////////////////////////////// - -} // end namespace Catch - -// end catch_test_case_registry_impl.h -// start catch_reporter_registry.h - -#include - -namespace Catch { - - class ReporterRegistry : public IReporterRegistry { - - public: - - ~ReporterRegistry() override; - - IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; - - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); - void registerListener( IReporterFactoryPtr const& factory ); - - FactoryMap const& getFactories() const override; - Listeners const& getListeners() const override; - - private: - FactoryMap m_factories; - Listeners m_listeners; - }; -} - -// end catch_reporter_registry.h -// start catch_tag_alias_registry.h - -// start catch_tag_alias.h - -#include - -namespace Catch { - - struct TagAlias { - TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); - - std::string tag; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - -// end catch_tag_alias.h -#include - -namespace Catch { - - class TagAliasRegistry : public ITagAliasRegistry { - public: - ~TagAliasRegistry() override; - TagAlias const* find( std::string const& alias ) const override; - std::string expandAliases( std::string const& unexpandedTestSpec ) const override; - void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); - - private: - std::map m_registry; - }; - -} // end namespace Catch - -// end catch_tag_alias_registry.h -// start catch_startup_exception_registry.h - -#include -#include - -namespace Catch { - - class StartupExceptionRegistry { - public: - void add(std::exception_ptr const& exception) noexcept; - std::vector const& getExceptions() const noexcept; - private: - std::vector m_exceptions; - }; - -} // end namespace Catch - -// end catch_startup_exception_registry.h -// start catch_singletons.hpp - -namespace Catch { - - struct ISingleton { - virtual ~ISingleton(); - }; - - void addSingleton( ISingleton* singleton ); - void cleanupSingletons(); - - template - class Singleton : SingletonImplT, public ISingleton { - - static auto getInternal() -> Singleton* { - static Singleton* s_instance = nullptr; - if( !s_instance ) { - s_instance = new Singleton; - addSingleton( s_instance ); - } - return s_instance; - } - - public: - static auto get() -> InterfaceT const& { - return *getInternal(); - } - static auto getMutable() -> MutableInterfaceT& { - return *getInternal(); - } - }; - -} // namespace Catch - -// end catch_singletons.hpp -namespace Catch { - - namespace { - - class RegistryHub : public IRegistryHub, public IMutableRegistryHub, - private NonCopyable { - - public: // IRegistryHub - RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { - return m_reporterRegistry; - } - ITestCaseRegistry const& getTestCaseRegistry() const override { - return m_testCaseRegistry; - } - IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { - return m_exceptionTranslatorRegistry; - } - ITagAliasRegistry const& getTagAliasRegistry() const override { - return m_tagAliasRegistry; - } - StartupExceptionRegistry const& getStartupExceptionRegistry() const override { - return m_exceptionRegistry; - } - - public: // IMutableRegistryHub - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerReporter( name, factory ); - } - void registerListener( IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerListener( factory ); - } - void registerTest( TestCase const& testInfo ) override { - m_testCaseRegistry.registerTest( testInfo ); - } - void registerTranslator( const IExceptionTranslator* translator ) override { - m_exceptionTranslatorRegistry.registerTranslator( translator ); - } - void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { - m_tagAliasRegistry.add( alias, tag, lineInfo ); - } - void registerStartupException() noexcept override { - m_exceptionRegistry.add(std::current_exception()); - } - - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - StartupExceptionRegistry m_exceptionRegistry; - }; - } - - using RegistryHubSingleton = Singleton; - - IRegistryHub const& getRegistryHub() { - return RegistryHubSingleton::get(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return RegistryHubSingleton::getMutable(); - } - void cleanUp() { - cleanupSingletons(); - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - -} // end namespace Catch -// end catch_registry_hub.cpp -// start catch_reporter_registry.cpp - -namespace Catch { - - ReporterRegistry::~ReporterRegistry() = default; - - IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( ReporterConfig( config ) ); - } - - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { - m_factories.emplace(name, factory); - } - void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { - m_listeners.push_back( factory ); - } - - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; - } - -} -// end catch_reporter_registry.cpp -// start catch_result_type.cpp - -namespace Catch { - - bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch -// end catch_result_type.cpp -// start catch_run_context.cpp - -#include -#include -#include - -namespace Catch { - - namespace Generators { - struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { - size_t m_index = static_cast( -1 ); - GeneratorBasePtr m_generator; - - GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - {} - ~GeneratorTracker(); - - static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { - std::shared_ptr tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = std::static_pointer_cast( childTracker ); - } - else { - tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker ); - currentTracker.addChild( tracker ); - } - - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; - } - - void moveNext() { - m_index++; - m_children.clear(); - } - - // TrackerBase interface - bool isIndexTracker() const override { return true; } - auto hasGenerator() const -> bool override { - return !!m_generator; - } - void close() override { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 ) - m_runState = Executing; - } - - // IGeneratorTracker interface - auto getGenerator() const -> GeneratorBasePtr const& override { - return m_generator; - } - void setGenerator( GeneratorBasePtr&& generator ) override { - m_generator = std::move( generator ); - } - auto getIndex() const -> size_t override { - return m_index; - } - }; - GeneratorTracker::~GeneratorTracker() {} - } - - RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) - : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), - m_config(_config), - m_reporter(std::move(reporter)), - m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, - m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) - { - m_context.setRunner(this); - m_context.setConfig(m_config); - m_context.setResultCapture(this); - m_reporter->testRunStarting(m_runInfo); - } - - RunContext::~RunContext() { - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); - } - - void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); - } - - void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); - } - - Totals RunContext::runTest(TestCase const& testCase) { - Totals prevTotals = m_totals; - - std::string redirectedCout; - std::string redirectedCerr; - - auto const& testInfo = testCase.getTestCaseInfo(); - - m_reporter->testCaseStarting(testInfo); - - m_activeTestCase = &testCase; - - ITracker& rootTracker = m_trackerContext.startRun(); - assert(rootTracker.isSectionTracker()); - static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); - do { - m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); - runCurrentTest(redirectedCout, redirectedCerr); - } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); - - Totals deltaTotals = m_totals.delta(prevTotals); - if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { - deltaTotals.assertions.failed++; - deltaTotals.testCases.passed--; - deltaTotals.testCases.failed++; - } - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting())); - - m_activeTestCase = nullptr; - m_testCaseTracker = nullptr; - - return deltaTotals; - } - - IConfigPtr RunContext::config() const { - return m_config; - } - - IStreamingReporter& RunContext::reporter() const { - return *m_reporter; - } - - void RunContext::assertionEnded(AssertionResult const & result) { - if (result.getResultType() == ResultWas::Ok) { - m_totals.assertions.passed++; - m_lastAssertionPassed = true; - } else if (!result.isOk()) { - m_lastAssertionPassed = false; - if( m_activeTestCase->getTestCaseInfo().okToFail() ) - m_totals.assertions.failedButOk++; - else - m_totals.assertions.failed++; - } - else { - m_lastAssertionPassed = true; - } - - // We have no use for the return value (whether messages should be cleared), because messages were made scoped - // and should be let to clear themselves out. - static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); - - // Reset working state - resetAssertionInfo(); - m_lastResult = result; - } - void RunContext::resetAssertionInfo() { - m_lastAssertionInfo.macroName = StringRef(); - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; - } - - bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { - ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); - if (!sectionTracker.isOpen()) - return false; - m_activeSections.push_back(§ionTracker); - - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - - m_reporter->sectionStarting(sectionInfo); - - assertions = m_totals.assertions; - - return true; - } - auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { - using namespace Generators; - GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); - assert( tracker.isOpen() ); - m_lastAssertionInfo.lineInfo = lineInfo; - return tracker; - } - - bool RunContext::testForMissingAssertions(Counts& assertions) { - if (assertions.total() != 0) - return false; - if (!m_config->warnAboutMissingAssertions()) - return false; - if (m_trackerContext.currentTracker().hasChildren()) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } - - void RunContext::sectionEnded(SectionEndInfo const & endInfo) { - Counts assertions = m_totals.assertions - endInfo.prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - - if (!m_activeSections.empty()) { - m_activeSections.back()->close(); - m_activeSections.pop_back(); - } - - m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); - m_messages.clear(); - } - - void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { - if (m_unfinishedSections.empty()) - m_activeSections.back()->fail(); - else - m_activeSections.back()->close(); - m_activeSections.pop_back(); - - m_unfinishedSections.push_back(endInfo); - } - void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { - m_reporter->benchmarkStarting( info ); - } - void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { - m_reporter->benchmarkEnded( stats ); - } - - void RunContext::pushScopedMessage(MessageInfo const & message) { - m_messages.push_back(message); - } - - void RunContext::popScopedMessage(MessageInfo const & message) { - m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); - } - - std::string RunContext::getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : std::string(); - } - - const AssertionResult * RunContext::getLastResult() const { - return &(*m_lastResult); - } - - void RunContext::exceptionEarlyReported() { - m_shouldReportUnexpected = false; - } - - void RunContext::handleFatalErrorCondition( StringRef message ) { - // First notify reporter that bad things happened - m_reporter->fatalErrorEncountered(message); - - // Don't rebuild the result -- the stringification itself can cause more fatal errors - // Instead, fake a result data. - AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); - tempResult.message = message; - AssertionResult result(m_lastAssertionInfo, tempResult); - - assertionEnded(result); - - handleUnfinishedSections(); - - // Recreate section for test case (as we will lose the one that was in scope) - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); - - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); - m_reporter->sectionEnded(testCaseSectionStats); - - auto const& testInfo = m_activeTestCase->getTestCaseInfo(); - - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - deltaTotals.assertions.failed = 1; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - std::string(), - std::string(), - false)); - m_totals.testCases.failed++; - testGroupEnded(std::string(), m_totals, 1, 1); - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); - } - - bool RunContext::lastAssertionPassed() { - return m_lastAssertionPassed; - } - - void RunContext::assertionPassed() { - m_lastAssertionPassed = true; - ++m_totals.assertions.passed; - resetAssertionInfo(); - } - - bool RunContext::aborting() const { - return m_totals.assertions.failed == static_cast(m_config->abortAfter()); - } - - void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); - m_reporter->sectionStarting(testCaseSection); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - m_shouldReportUnexpected = true; - m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; - - seedRng(*m_config); - - Timer timer; - CATCH_TRY { - if (m_reporter->getPreferences().shouldRedirectStdOut) { -#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) - RedirectedStdOut redirectedStdOut; - RedirectedStdErr redirectedStdErr; - - timer.start(); - invokeActiveTestCase(); - redirectedCout += redirectedStdOut.str(); - redirectedCerr += redirectedStdErr.str(); -#else - OutputRedirect r(redirectedCout, redirectedCerr); - timer.start(); - invokeActiveTestCase(); -#endif - } else { - timer.start(); - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } CATCH_CATCH_ANON (TestFailureException&) { - // This just means the test was aborted due to failure - } CATCH_CATCH_ALL { - // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions - // are reported without translation at the point of origin. - if( m_shouldReportUnexpected ) { - AssertionReaction dummyReaction; - handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); - } - } - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - - m_testCaseTracker->close(); - handleUnfinishedSections(); - m_messages.clear(); - - SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); - m_reporter->sectionEnded(testCaseSectionStats); - } - - void RunContext::invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } - - void RunContext::handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for (auto it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it) - sectionEnded(*it); - m_unfinishedSections.clear(); - } - - void RunContext::handleExpr( - AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction - ) { - m_reporter->assertionStarting( info ); - - bool negated = isFalseTest( info.resultDisposition ); - bool result = expr.getResult() != negated; - - if( result ) { - if (!m_includeSuccessfulResults) { - assertionPassed(); - } - else { - reportExpr(info, ResultWas::Ok, &expr, negated); - } - } - else { - reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); - populateReaction( reaction ); - } - } - void RunContext::reportExpr( - AssertionInfo const &info, - ResultWas::OfType resultType, - ITransientExpression const *expr, - bool negated ) { - - m_lastAssertionInfo = info; - AssertionResultData data( resultType, LazyExpression( negated ) ); - - AssertionResult assertionResult{ info, data }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - - assertionEnded( assertionResult ); - } - - void RunContext::handleMessage( - AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef const& message, - AssertionReaction& reaction - ) { - m_reporter->assertionStarting( info ); - - m_lastAssertionInfo = info; - - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; - AssertionResult assertionResult{ m_lastAssertionInfo, data }; - assertionEnded( assertionResult ); - if( !assertionResult.isOk() ) - populateReaction( reaction ); - } - void RunContext::handleUnexpectedExceptionNotThrown( - AssertionInfo const& info, - AssertionReaction& reaction - ) { - handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); - } - - void RunContext::handleUnexpectedInflightException( - AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = message; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); - populateReaction( reaction ); - } - - void RunContext::populateReaction( AssertionReaction& reaction ) { - reaction.shouldDebugBreak = m_config->shouldDebugBreak(); - reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); - } - - void RunContext::handleIncomplete( - AssertionInfo const& info - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); - } - void RunContext::handleNonExpr( - AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( resultType, LazyExpression( false ) ); - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); - - if( !assertionResult.isOk() ) - populateReaction( reaction ); - } - - IResultCapture& getResultCapture() { - if (auto* capture = getCurrentContext().getResultCapture()) - return *capture; - else - CATCH_INTERNAL_ERROR("No result capture instance"); - } -} -// end catch_run_context.cpp -// start catch_section.cpp - -namespace Catch { - - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); - } - - Section::~Section() { - if( m_sectionIncluded ) { - SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; - if( uncaught_exceptions() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); - } - } - - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } - -} // end namespace Catch -// end catch_section.cpp -// start catch_section_info.cpp - -namespace Catch { - - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name ) - : name( _name ), - lineInfo( _lineInfo ) - {} - -} // end namespace Catch -// end catch_section_info.cpp -// start catch_session.cpp - -// start catch_session.h - -#include - -namespace Catch { - - class Session : NonCopyable { - public: - - Session(); - ~Session() override; - - void showHelp() const; - void libIdentify(); - - int applyCommandLine( int argc, char const * const * argv ); - - void useConfigData( ConfigData const& configData ); - - int run( int argc, char* argv[] ); - #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) - int run( int argc, wchar_t* const argv[] ); - #endif - int run(); - - clara::Parser const& cli() const; - void cli( clara::Parser const& newParser ); - ConfigData& configData(); - Config& config(); - private: - int runInternal(); - - clara::Parser m_cli; - ConfigData m_configData; - std::shared_ptr m_config; - bool m_startupExceptions = false; - }; - -} // end namespace Catch - -// end catch_session.h -// start catch_version.h - -#include - -namespace Catch { - - // Versioning information - struct Version { - Version( Version const& ) = delete; - Version& operator=( Version const& ) = delete; - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ); - - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const patchNumber; - - // buildNumber is only used if branchName is not null - char const * const branchName; - unsigned int const buildNumber; - - friend std::ostream& operator << ( std::ostream& os, Version const& version ); - }; - - Version const& libraryVersion(); -} - -// end catch_version.h -#include -#include - -namespace Catch { - - namespace { - const int MaxExitCode = 255; - - IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { - auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); - CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); - - return reporter; - } - - IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { - if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { - return createReporter(config->getReporterName(), config); - } - - auto multi = std::unique_ptr(new ListeningReporter); - - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) { - multi->addListener(listener->create(Catch::ReporterConfig(config))); - } - multi->addReporter(createReporter(config->getReporterName(), config)); - return std::move(multi); - } - - Catch::Totals runTests(std::shared_ptr const& config) { - // FixMe: Add listeners in order first, then add reporters. - - auto reporter = makeReporter(config); - - RunContext context(config, std::move(reporter)); - - Totals totals; - - context.testGroupStarting(config->name(), 1, 1); - - TestSpec testSpec = config->testSpec(); - - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); - } - - if (config->warnAboutNoTests() && totals.testCases.total() == 0) { - ReusableStringStream testConfig; - - bool first = true; - for (const auto& input : config->getTestsOrTags()) { - if (!first) { testConfig << ' '; } - first = false; - testConfig << input; - } - - context.reporter().noMatchingTestCases(testConfig.str()); - totals.error = -1; - } - - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } - - void applyFilenamesAsTags(Catch::IConfig const& config) { - auto& tests = const_cast&>(getAllTestCasesSorted(config)); - for (auto& testCase : tests) { - auto tags = testCase.tags; - - std::string filename = testCase.lineInfo.file; - auto lastSlash = filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - filename.erase(0, lastSlash); - filename[0] = '#'; - } - - auto lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - filename.erase(lastDot); - } - - tags.push_back(std::move(filename)); - setTags(testCase, tags); - } - } - - } // anon namespace - - Session::Session() { - static bool alreadyInstantiated = false; - if( alreadyInstantiated ) { - CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } - CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } - } - - // There cannot be exceptions at startup in no-exception mode. -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); - if ( !exceptions.empty() ) { - m_startupExceptions = true; - Colour colourGuard( Colour::Red ); - Catch::cerr() << "Errors occurred during startup!" << '\n'; - // iterate over all exceptions and notify user - for ( const auto& ex_ptr : exceptions ) { - try { - std::rethrow_exception(ex_ptr); - } catch ( std::exception const& ex ) { - Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; - } - } - } -#endif - - alreadyInstantiated = true; - m_cli = makeCommandLineParser( m_configData ); - } - Session::~Session() { - Catch::cleanUp(); - } - - void Session::showHelp() const { - Catch::cout() - << "\nCatch v" << libraryVersion() << "\n" - << m_cli << std::endl - << "For more detailed usage please see the project docs\n" << std::endl; - } - void Session::libIdentify() { - Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch test executable\n" - << std::left << std::setw(16) << "category: " << "testframework\n" - << std::left << std::setw(16) << "framework: " << "Catch Test\n" - << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; - } - - int Session::applyCommandLine( int argc, char const * const * argv ) { - if( m_startupExceptions ) - return 1; - - auto result = m_cli.parse( clara::Args( argc, argv ) ); - if( !result ) { - Catch::cerr() - << Colour( Colour::Red ) - << "\nError(s) in input:\n" - << Column( result.errorMessage() ).indent( 2 ) - << "\n\n"; - Catch::cerr() << "Run with -? for usage\n" << std::endl; - return MaxExitCode; - } - - if( m_configData.showHelp ) - showHelp(); - if( m_configData.libIdentify ) - libIdentify(); - m_config.reset(); - return 0; - } - - void Session::useConfigData( ConfigData const& configData ) { - m_configData = configData; - m_config.reset(); - } - - int Session::run( int argc, char* argv[] ) { - if( m_startupExceptions ) - return 1; - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } - -#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) - int Session::run( int argc, wchar_t* const argv[] ) { - - char **utf8Argv = new char *[ argc ]; - - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); - - utf8Argv[ i ] = new char[ bufSize ]; - - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); - } - - int returnCode = run( argc, utf8Argv ); - - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; - - delete [] utf8Argv; - - return returnCode; - } -#endif - int Session::run() { - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before starting" << std::endl; - static_cast(std::getchar()); - } - int exitCode = runInternal(); - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; - static_cast(std::getchar()); - } - return exitCode; - } - - clara::Parser const& Session::cli() const { - return m_cli; - } - void Session::cli( clara::Parser const& newParser ) { - m_cli = newParser; - } - ConfigData& Session::configData() { - return m_configData; - } - Config& Session::config() { - if( !m_config ) - m_config = std::make_shared( m_configData ); - return *m_config; - } - - int Session::runInternal() { - if( m_startupExceptions ) - return 1; - - if (m_configData.showHelp || m_configData.libIdentify) { - return 0; - } - - CATCH_TRY { - config(); // Force config to be constructed - - seedRng( *m_config ); - - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); - - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); - - auto totals = runTests( m_config ); - // Note that on unices only the lower 8 bits are usually used, clamping - // the return value to 255 prevents false negative when some multiple - // of 256 tests has failed - return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); - } -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return MaxExitCode; - } -#endif - } - -} // end namespace Catch -// end catch_session.cpp -// start catch_singletons.cpp - -#include - -namespace Catch { - - namespace { - static auto getSingletons() -> std::vector*& { - static std::vector* g_singletons = nullptr; - if( !g_singletons ) - g_singletons = new std::vector(); - return g_singletons; - } - } - - ISingleton::~ISingleton() {} - - void addSingleton(ISingleton* singleton ) { - getSingletons()->push_back( singleton ); - } - void cleanupSingletons() { - auto& singletons = getSingletons(); - for( auto singleton : *singletons ) - delete singleton; - delete singletons; - singletons = nullptr; - } - -} // namespace Catch -// end catch_singletons.cpp -// start catch_startup_exception_registry.cpp - -namespace Catch { -void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { - CATCH_TRY { - m_exceptions.push_back(exception); - } CATCH_CATCH_ALL { - // If we run out of memory during start-up there's really not a lot more we can do about it - std::terminate(); - } - } - - std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { - return m_exceptions; - } - -} // end namespace Catch -// end catch_startup_exception_registry.cpp -// start catch_stream.cpp - -#include -#include -#include -#include -#include -#include - -namespace Catch { - - Catch::IStream::~IStream() = default; - - namespace detail { namespace { - template - class StreamBufImpl : public std::streambuf { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } - - ~StreamBufImpl() noexcept { - StreamBufImpl::sync(); - } - - private: - int overflow( int c ) override { - sync(); - - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() override { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - struct OutputDebugWriter { - - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; - - /////////////////////////////////////////////////////////////////////////// - - class FileStream : public IStream { - mutable std::ofstream m_ofs; - public: - FileStream( StringRef filename ) { - m_ofs.open( filename.c_str() ); - CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); - } - ~FileStream() override = default; - public: // IStream - std::ostream& stream() const override { - return m_ofs; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - class CoutStream : public IStream { - mutable std::ostream m_os; - public: - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream() : m_os( Catch::cout().rdbuf() ) {} - ~CoutStream() override = default; - - public: // IStream - std::ostream& stream() const override { return m_os; } - }; - - /////////////////////////////////////////////////////////////////////////// - - class DebugOutStream : public IStream { - std::unique_ptr> m_streamBuf; - mutable std::ostream m_os; - public: - DebugOutStream() - : m_streamBuf( new StreamBufImpl() ), - m_os( m_streamBuf.get() ) - {} - - ~DebugOutStream() override = default; - - public: // IStream - std::ostream& stream() const override { return m_os; } - }; - - }} // namespace anon::detail - - /////////////////////////////////////////////////////////////////////////// - - auto makeStream( StringRef const &filename ) -> IStream const* { - if( filename.empty() ) - return new detail::CoutStream(); - else if( filename[0] == '%' ) { - if( filename == "%debug" ) - return new detail::DebugOutStream(); - else - CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); - } - else - return new detail::FileStream( filename ); - } - - // This class encapsulates the idea of a pool of ostringstreams that can be reused. - struct StringStreams { - std::vector> m_streams; - std::vector m_unused; - std::ostringstream m_referenceStream; // Used for copy state/ flags from - - auto add() -> std::size_t { - if( m_unused.empty() ) { - m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); - return m_streams.size()-1; - } - else { - auto index = m_unused.back(); - m_unused.pop_back(); - return index; - } - } - - void release( std::size_t index ) { - m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state - m_unused.push_back(index); - } - }; - - ReusableStringStream::ReusableStringStream() - : m_index( Singleton::getMutable().add() ), - m_oss( Singleton::getMutable().m_streams[m_index].get() ) - {} - - ReusableStringStream::~ReusableStringStream() { - static_cast( m_oss )->str(""); - m_oss->clear(); - Singleton::getMutable().release( m_index ); - } - - auto ReusableStringStream::str() const -> std::string { - return static_cast( m_oss )->str(); - } - - /////////////////////////////////////////////////////////////////////////// - -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions - std::ostream& cout() { return std::cout; } - std::ostream& cerr() { return std::cerr; } - std::ostream& clog() { return std::clog; } -#endif -} -// end catch_stream.cpp -// start catch_string_manip.cpp - -#include -#include -#include -#include - -namespace Catch { - - namespace { - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } - } - - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); - } - bool startsWith( std::string const& s, char prefix ) { - return !s.empty() && s[0] == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); - } - bool endsWith( std::string const& s, char suffix ) { - return !s.empty() && s[s.size()-1] == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); - - return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); - } - - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } - - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} - - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << ' ' << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << 's'; - return os; - } - -} -// end catch_string_manip.cpp -// start catch_stringref.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -#include -#include -#include - -namespace { - const uint32_t byte_2_lead = 0xC0; - const uint32_t byte_3_lead = 0xE0; - const uint32_t byte_4_lead = 0xF0; -} - -namespace Catch { - StringRef::StringRef( char const* rawChars ) noexcept - : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) - {} - - StringRef::operator std::string() const { - return std::string( m_start, m_size ); - } - - void StringRef::swap( StringRef& other ) noexcept { - std::swap( m_start, other.m_start ); - std::swap( m_size, other.m_size ); - std::swap( m_data, other.m_data ); - } - - auto StringRef::c_str() const -> char const* { - if( isSubstring() ) - const_cast( this )->takeOwnership(); - return m_start; - } - auto StringRef::currentData() const noexcept -> char const* { - return m_start; - } - - auto StringRef::isOwned() const noexcept -> bool { - return m_data != nullptr; - } - auto StringRef::isSubstring() const noexcept -> bool { - return m_start[m_size] != '\0'; - } - - void StringRef::takeOwnership() { - if( !isOwned() ) { - m_data = new char[m_size+1]; - memcpy( m_data, m_start, m_size ); - m_data[m_size] = '\0'; - m_start = m_data; - } - } - auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { - if( start < m_size ) - return StringRef( m_start+start, size ); - else - return StringRef(); - } - auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { - return - size() == other.size() && - (std::strncmp( m_start, other.m_start, size() ) == 0); - } - auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { - return !operator==( other ); - } - - auto StringRef::operator[](size_type index) const noexcept -> char { - return m_start[index]; - } - - auto StringRef::numberOfCharacters() const noexcept -> size_type { - size_type noChars = m_size; - // Make adjustments for uft encodings - for( size_type i=0; i < m_size; ++i ) { - char c = m_start[i]; - if( ( c & byte_2_lead ) == byte_2_lead ) { - noChars--; - if (( c & byte_3_lead ) == byte_3_lead ) - noChars--; - if( ( c & byte_4_lead ) == byte_4_lead ) - noChars--; - } - } - return noChars; - } - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { - std::string str; - str.reserve( lhs.size() + rhs.size() ); - str += lhs; - str += rhs; - return str; - } - auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - - auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os.write(str.currentData(), str.size()); - } - - auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { - lhs.append(rhs.currentData(), rhs.size()); - return lhs; - } - -} // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -// end catch_stringref.cpp -// start catch_tag_alias.cpp - -namespace Catch { - TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} -} -// end catch_tag_alias.cpp -// start catch_tag_alias_autoregistrar.cpp - -namespace Catch { - - RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { - CATCH_TRY { - getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); - } CATCH_CATCH_ALL { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - -} -// end catch_tag_alias_autoregistrar.cpp -// start catch_tag_alias_registry.cpp - -#include - -namespace Catch { - - TagAliasRegistry::~TagAliasRegistry() {} - - TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { - auto it = m_registry.find( alias ); - if( it != m_registry.end() ) - return &(it->second); - else - return nullptr; - } - - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( auto const& registryKvp : m_registry ) { - std::size_t pos = expandedTestSpec.find( registryKvp.first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - registryKvp.second.tag + - expandedTestSpec.substr( pos + registryKvp.first.size() ); - } - } - return expandedTestSpec; - } - - void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { - CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), - "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); - - CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, - "error: tag alias, '" << alias << "' already registered.\n" - << "\tFirst seen at: " << find(alias)->lineInfo << "\n" - << "\tRedefined at: " << lineInfo ); - } - - ITagAliasRegistry::~ITagAliasRegistry() {} - - ITagAliasRegistry const& ITagAliasRegistry::get() { - return getRegistryHub().getTagAliasRegistry(); - } - -} // end namespace Catch -// end catch_tag_alias_registry.cpp -// start catch_test_case_info.cpp - -#include -#include -#include -#include - -namespace Catch { - - namespace { - TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else if( tag == "!benchmark" ) - return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); - else - return TestCaseInfo::None; - } - bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); - } - void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - CATCH_ENFORCE( !isReservedTag(tag), - "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" - << _lineInfo ); - } - } - - TestCase makeTestCase( ITestInvoker* _testCase, - std::string const& _className, - NameAndTags const& nameAndTags, - SourceLineInfo const& _lineInfo ) - { - bool isHidden = false; - - // Parse out tags - std::vector tags; - std::string desc, tag; - bool inTag = false; - std::string _descOrTags = nameAndTags.tags; - for (char c : _descOrTags) { - if( !inTag ) { - if( c == '[' ) - inTag = true; - else - desc += c; - } - else { - if( c == ']' ) { - TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( ( prop & TestCaseInfo::IsHidden ) != 0 ) - isHidden = true; - else if( prop == TestCaseInfo::None ) - enforceNotReservedTag( tag, _lineInfo ); - - tags.push_back( tag ); - tag.clear(); - inTag = false; - } - else - tag += c; - } - } - if( isHidden ) { - tags.push_back( "." ); - } - - TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, std::move(info) ); - } - - void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { - std::sort(begin(tags), end(tags)); - tags.erase(std::unique(begin(tags), end(tags)), end(tags)); - testCaseInfo.lcaseTags.clear(); - - for( auto const& tag : tags ) { - std::string lcaseTag = toLower( tag ); - testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); - testCaseInfo.lcaseTags.push_back( lcaseTag ); - } - testCaseInfo.tags = std::move(tags); - } - - TestCaseInfo::TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::vector const& _tags, - SourceLineInfo const& _lineInfo ) - : name( _name ), - className( _className ), - description( _description ), - lineInfo( _lineInfo ), - properties( None ) - { - setTags( *this, _tags ); - } - - bool TestCaseInfo::isHidden() const { - return ( properties & IsHidden ) != 0; - } - bool TestCaseInfo::throws() const { - return ( properties & Throws ) != 0; - } - bool TestCaseInfo::okToFail() const { - return ( properties & (ShouldFail | MayFail ) ) != 0; - } - bool TestCaseInfo::expectedToFail() const { - return ( properties & (ShouldFail ) ) != 0; - } - - std::string TestCaseInfo::tagsAsString() const { - std::string ret; - // '[' and ']' per tag - std::size_t full_size = 2 * tags.size(); - for (const auto& tag : tags) { - full_size += tag.size(); - } - ret.reserve(full_size); - for (const auto& tag : tags) { - ret.push_back('['); - ret.append(tag); - ret.push_back(']'); - } - - return ret; - } - - TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} - - TestCase TestCase::withName( std::string const& _newName ) const { - TestCase other( *this ); - other.name = _newName; - return other; - } - - void TestCase::invoke() const { - test->invoke(); - } - - bool TestCase::operator == ( TestCase const& other ) const { - return test.get() == other.test.get() && - name == other.name && - className == other.className; - } - - bool TestCase::operator < ( TestCase const& other ) const { - return name < other.name; - } - - TestCaseInfo const& TestCase::getTestCaseInfo() const - { - return *this; - } - -} // end namespace Catch -// end catch_test_case_info.cpp -// start catch_test_case_registry_impl.cpp - -#include - -namespace Catch { - - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { - - std::vector sorted = unsortedTestCases; - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - seedRng( config ); - std::shuffle( sorted.begin(), sorted.end(), rng() ); - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - return sorted; - } - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); - } - - void enforceNoDuplicateTestCases( std::vector const& functions ) { - std::set seenFunctions; - for( auto const& function : functions ) { - auto prev = seenFunctions.insert( function ); - CATCH_ENFORCE( prev.second, - "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); - } - } - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { - std::vector filtered; - filtered.reserve( testCases.size() ); - for( auto const& testCase : testCases ) - if( matchTest( testCase, testSpec, config ) ) - filtered.push_back( testCase ); - return filtered; - } - std::vector const& getAllTestCasesSorted( IConfig const& config ) { - return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); - } - - void TestRegistry::registerTest( TestCase const& testCase ) { - std::string name = testCase.getTestCaseInfo().name; - if( name.empty() ) { - ReusableStringStream rss; - rss << "Anonymous test case " << ++m_unnamedCount; - return registerTest( testCase.withName( rss.str() ) ); - } - m_functions.push_back( testCase ); - } - - std::vector const& TestRegistry::getAllTests() const { - return m_functions; - } - std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { - if( m_sortedFunctions.empty() ) - enforceNoDuplicateTestCases( m_functions ); - - if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { - m_sortedFunctions = sortTests( config, m_functions ); - m_currentSortOrder = config.runOrder(); - } - return m_sortedFunctions; - } - - /////////////////////////////////////////////////////////////////////////// - TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} - - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } - - std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, '&' ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } - -} // end namespace Catch -// end catch_test_case_registry_impl.cpp -// start catch_test_case_tracker.cpp - -#include -#include -#include -#include -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -namespace Catch { -namespace TestCaseTracking { - - NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), - location( _location ) - {} - - ITracker::~ITracker() = default; - - TrackerContext& TrackerContext::instance() { - static TrackerContext s_instance; - return s_instance; - } - - ITracker& TrackerContext::startRun() { - m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); - m_currentTracker = nullptr; - m_runState = Executing; - return *m_rootTracker; - } - - void TrackerContext::endRun() { - m_rootTracker.reset(); - m_currentTracker = nullptr; - m_runState = NotStarted; - } - - void TrackerContext::startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } - void TrackerContext::completeCycle() { - m_runState = CompletedCycle; - } - - bool TrackerContext::completedCycle() const { - return m_runState == CompletedCycle; - } - ITracker& TrackerContext::currentTracker() { - return *m_currentTracker; - } - void TrackerContext::setCurrentTracker( ITracker* tracker ) { - m_currentTracker = tracker; - } - - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), - m_ctx( ctx ), - m_parent( parent ) - {} - - NameAndLocation const& TrackerBase::nameAndLocation() const { - return m_nameAndLocation; - } - bool TrackerBase::isComplete() const { - return m_runState == CompletedSuccessfully || m_runState == Failed; - } - bool TrackerBase::isSuccessfullyCompleted() const { - return m_runState == CompletedSuccessfully; - } - bool TrackerBase::isOpen() const { - return m_runState != NotStarted && !isComplete(); - } - bool TrackerBase::hasChildren() const { - return !m_children.empty(); - } - - void TrackerBase::addChild( ITrackerPtr const& child ) { - m_children.push_back( child ); - } - - ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { - auto it = std::find_if( m_children.begin(), m_children.end(), - [&nameAndLocation]( ITrackerPtr const& tracker ){ - return - tracker->nameAndLocation().location == nameAndLocation.location && - tracker->nameAndLocation().name == nameAndLocation.name; - } ); - return( it != m_children.end() ) - ? *it - : nullptr; - } - ITracker& TrackerBase::parent() { - assert( m_parent ); // Should always be non-null except for root - return *m_parent; - } - - void TrackerBase::openChild() { - if( m_runState != ExecutingChildren ) { - m_runState = ExecutingChildren; - if( m_parent ) - m_parent->openChild(); - } - } - - bool TrackerBase::isSectionTracker() const { return false; } - bool TrackerBase::isIndexTracker() const { return false; } - - void TrackerBase::open() { - m_runState = Executing; - moveToThis(); - if( m_parent ) - m_parent->openChild(); - } - - void TrackerBase::close() { - - // Close any still open children (e.g. generators) - while( &m_ctx.currentTracker() != this ) - m_ctx.currentTracker().close(); - - switch( m_runState ) { - case NeedsAnotherRun: - break; - - case Executing: - m_runState = CompletedSuccessfully; - break; - case ExecutingChildren: - if( m_children.empty() || m_children.back()->isComplete() ) - m_runState = CompletedSuccessfully; - break; - - case NotStarted: - case CompletedSuccessfully: - case Failed: - CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); - - default: - CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); - } - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::fail() { - m_runState = Failed; - if( m_parent ) - m_parent->markAsNeedingAnotherRun(); - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::markAsNeedingAnotherRun() { - m_runState = NeedsAnotherRun; - } - - void TrackerBase::moveToParent() { - assert( m_parent ); - m_ctx.setCurrentTracker( m_parent ); - } - void TrackerBase::moveToThis() { - m_ctx.setCurrentTracker( this ); - } - - SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - { - if( parent ) { - while( !parent->isSectionTracker() ) - parent = &parent->parent(); - - SectionTracker& parentSection = static_cast( *parent ); - addNextFilters( parentSection.m_filters ); - } - } - - bool SectionTracker::isSectionTracker() const { return true; } - - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - std::shared_ptr section; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isSectionTracker() ); - section = std::static_pointer_cast( childTracker ); - } - else { - section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); - currentTracker.addChild( section ); - } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; - } - - void SectionTracker::tryOpen() { - if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) - open(); - } - - void SectionTracker::addInitialFilters( std::vector const& filters ) { - if( !filters.empty() ) { - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void SectionTracker::addNextFilters( std::vector const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); - } - - IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_size( size ) - {} - - bool IndexTracker::isIndexTracker() const { return true; } - - IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { - std::shared_ptr tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = std::static_pointer_cast( childTracker ); - } - else { - tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); - } - - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; - } - - int IndexTracker::index() const { return m_index; } - - void IndexTracker::moveNext() { - m_index++; - m_children.clear(); - } - - void IndexTracker::close() { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) - m_runState = Executing; - } - -} // namespace TestCaseTracking - -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; - -} // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -// end catch_test_case_tracker.cpp -// start catch_test_registry.cpp - -namespace Catch { - - auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); - } - - NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} - - AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { - CATCH_TRY { - getMutableRegistryHub() - .registerTest( - makeTestCase( - invoker, - extractClassName( classOrMethod ), - nameAndTags, - lineInfo)); - } CATCH_CATCH_ALL { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - - AutoReg::~AutoReg() = default; -} -// end catch_test_registry.cpp -// start catch_test_spec.cpp - -#include -#include -#include -#include - -namespace Catch { - - TestSpec::Pattern::~Pattern() = default; - TestSpec::NamePattern::~NamePattern() = default; - TestSpec::TagPattern::~TagPattern() = default; - TestSpec::ExcludedPattern::~ExcludedPattern() = default; - - TestSpec::NamePattern::NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), CaseSensitive::No ) - {} - bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( toLower( testCase.name ) ); - } - - TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} - bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { - return std::find(begin(testCase.lcaseTags), - end(testCase.lcaseTags), - m_tag) != end(testCase.lcaseTags); - } - - TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } - - bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( auto const& pattern : m_patterns ) { - if( !pattern->matches( testCase ) ) - return false; - } - return true; - } - - bool TestSpec::hasFilters() const { - return !m_filters.empty(); - } - bool TestSpec::matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( auto const& filter : m_filters ) - if( filter.matches( testCase ) ) - return true; - return false; - } -} -// end catch_test_spec.cpp -// start catch_test_spec_parser.cpp - -namespace Catch { - - TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} - - TestSpecParser& TestSpecParser::parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - m_escapeChars.clear(); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern(); - return *this; - } - TestSpec TestSpecParser::testSpec() { - addFilter(); - return m_testSpec; - } - - void TestSpecParser::visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - case '\\': return escape(); - default: startNewMode( Name, m_pos ); break; - } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern(); - startNewMode( Tag, ++m_pos ); - } - else if( c == '\\' ) - escape(); - } - else if( m_mode == EscapedName ) - m_mode = Name; - else if( m_mode == QuotedName && c == '"' ) - addPattern(); - else if( m_mode == Tag && c == ']' ) - addPattern(); - } - void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - void TestSpecParser::escape() { - if( m_mode == None ) - m_start = m_pos; - m_mode = EscapedName; - m_escapeChars.push_back( m_pos ); - } - std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } - - void TestSpecParser::addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); - } - } - - TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } - -} // namespace Catch -// end catch_test_spec_parser.cpp -// start catch_timer.cpp - -#include - -static const uint64_t nanosecondsInSecond = 1000000000; - -namespace Catch { - - auto getCurrentNanosecondsSinceEpoch() -> uint64_t { - return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); - } - - namespace { - auto estimateClockResolution() -> uint64_t { - uint64_t sum = 0; - static const uint64_t iterations = 1000000; - - auto startTime = getCurrentNanosecondsSinceEpoch(); - - for( std::size_t i = 0; i < iterations; ++i ) { - - uint64_t ticks; - uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); - do { - ticks = getCurrentNanosecondsSinceEpoch(); - } while( ticks == baseTicks ); - - auto delta = ticks - baseTicks; - sum += delta; - - // If we have been calibrating for over 3 seconds -- the clock - // is terrible and we should move on. - // TBD: How to signal that the measured resolution is probably wrong? - if (ticks > startTime + 3 * nanosecondsInSecond) { - return sum / i; - } - } - - // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers - // - and potentially do more iterations if there's a high variance. - return sum/iterations; - } - } - auto getEstimatedClockResolution() -> uint64_t { - static auto s_resolution = estimateClockResolution(); - return s_resolution; - } - - void Timer::start() { - m_nanoseconds = getCurrentNanosecondsSinceEpoch(); - } - auto Timer::getElapsedNanoseconds() const -> uint64_t { - return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; - } - auto Timer::getElapsedMicroseconds() const -> uint64_t { - return getElapsedNanoseconds()/1000; - } - auto Timer::getElapsedMilliseconds() const -> unsigned int { - return static_cast(getElapsedMicroseconds()/1000); - } - auto Timer::getElapsedSeconds() const -> double { - return getElapsedMicroseconds()/1000000.0; - } - -} // namespace Catch -// end catch_timer.cpp -// start catch_tostring.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -# pragma clang diagnostic ignored "-Wglobal-constructors" -#endif - -// Enable specific decls locally -#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -#endif - -#include -#include - -namespace Catch { - -namespace Detail { - - const std::string unprintableString = "{?}"; - - namespace { - const int hexThreshold = 255; - - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; - - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; - } - }; - } - - std::string rawMemoryToString( const void *object, std::size_t size ) { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; - } - - unsigned char const *bytes = static_cast(object); - ReusableStringStream rss; - rss << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - rss << std::setw(2) << static_cast(bytes[i]); - return rss.str(); - } -} - -template -std::string fpToString( T value, int precision ) { - if (std::isnan(value)) { - return "nan"; - } - - ReusableStringStream rss; - rss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = rss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); - } - return d; -} - -//// ======================================================= //// -// -// Out-of-line defs for full specialization of StringMaker -// -//// ======================================================= //// - -std::string StringMaker::convert(const std::string& str) { - if (!getCurrentContext().getConfig()->showInvisibles()) { - return '"' + str + '"'; - } - - std::string s("\""); - for (char c : str) { - switch (c) { - case '\n': - s.append("\\n"); - break; - case '\t': - s.append("\\t"); - break; - default: - s.push_back(c); - break; - } - } - s.append("\""); - return s; -} - -#ifdef CATCH_CONFIG_WCHAR -std::string StringMaker::convert(const std::wstring& wstr) { - std::string s; - s.reserve(wstr.size()); - for (auto c : wstr) { - s += (c <= 0xff) ? static_cast(c) : '?'; - } - return ::Catch::Detail::stringify(s); -} -#endif - -std::string StringMaker::convert(char const* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(char* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } -} -#ifdef CATCH_CONFIG_WCHAR -std::string StringMaker::convert(wchar_t const * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(wchar_t * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -#endif - -std::string StringMaker::convert(int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long long value) { - ReusableStringStream rss; - rss << value; - if (value > Detail::hexThreshold) { - rss << " (0x" << std::hex << value << ')'; - } - return rss.str(); -} - -std::string StringMaker::convert(unsigned int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long long value) { - ReusableStringStream rss; - rss << value; - if (value > Detail::hexThreshold) { - rss << " (0x" << std::hex << value << ')'; - } - return rss.str(); -} - -std::string StringMaker::convert(bool b) { - return b ? "true" : "false"; -} - -std::string StringMaker::convert(char value) { - if (value == '\r') { - return "'\\r'"; - } else if (value == '\f') { - return "'\\f'"; - } else if (value == '\n') { - return "'\\n'"; - } else if (value == '\t') { - return "'\\t'"; - } else if ('\0' <= value && value < ' ') { - return ::Catch::Detail::stringify(static_cast(value)); - } else { - char chstr[] = "' '"; - chstr[1] = value; - return chstr; - } -} -std::string StringMaker::convert(signed char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} -std::string StringMaker::convert(unsigned char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} - -std::string StringMaker::convert(std::nullptr_t) { - return "nullptr"; -} - -std::string StringMaker::convert(float value) { - return fpToString(value, 5) + 'f'; -} -std::string StringMaker::convert(double value) { - return fpToString(value, 10); -} - -std::string ratio_string::symbol() { return "a"; } -std::string ratio_string::symbol() { return "f"; } -std::string ratio_string::symbol() { return "p"; } -std::string ratio_string::symbol() { return "n"; } -std::string ratio_string::symbol() { return "u"; } -std::string ratio_string::symbol() { return "m"; } - -} // end namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -// end catch_tostring.cpp -// start catch_totals.cpp - -namespace Catch { - - Counts Counts::operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } - - Counts& Counts::operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } - - std::size_t Counts::total() const { - return passed + failed + failedButOk; - } - bool Counts::allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool Counts::allOk() const { - return failed == 0; - } - - Totals Totals::operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } - - Totals& Totals::operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } - - Totals Totals::delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } - -} -// end catch_totals.cpp -// start catch_uncaught_exceptions.cpp - -#include - -namespace Catch { - bool uncaught_exceptions() { -#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) - return std::uncaught_exceptions() > 0; -#else - return std::uncaught_exception(); -#endif - } -} // end namespace Catch -// end catch_uncaught_exceptions.cpp -// start catch_version.cpp - -#include - -namespace Catch { - - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} - - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << '.' - << version.minorVersion << '.' - << version.patchNumber; - // branchName is never null -> 0th char is \0 if it is empty - if (version.branchName[0]) { - os << '-' << version.branchName - << '.' << version.buildNumber; - } - return os; - } - - Version const& libraryVersion() { - static Version version( 2, 4, 0, "", 0 ); - return version; - } - -} -// end catch_version.cpp -// start catch_wildcard_pattern.cpp - -#include - -namespace Catch { - - WildcardPattern::WildcardPattern( std::string const& pattern, - CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_pattern( adjustCase( pattern ) ) - { - if( startsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } - - bool WildcardPattern::matches( std::string const& str ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_pattern == adjustCase( str ); - case WildcardAtStart: - return endsWith( adjustCase( str ), m_pattern ); - case WildcardAtEnd: - return startsWith( adjustCase( str ), m_pattern ); - case WildcardAtBothEnds: - return contains( adjustCase( str ), m_pattern ); - default: - CATCH_INTERNAL_ERROR( "Unknown enum" ); - } - } - - std::string WildcardPattern::adjustCase( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; - } -} -// end catch_wildcard_pattern.cpp -// start catch_xmlwriter.cpp - -#include - -using uchar = unsigned char; - -namespace Catch { - -namespace { - - size_t trailingBytes(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return 2; - } - if ((c & 0xF0) == 0xE0) { - return 3; - } - if ((c & 0xF8) == 0xF0) { - return 4; - } - CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - uint32_t headerValue(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return c & 0x1F; - } - if ((c & 0xF0) == 0xE0) { - return c & 0x0F; - } - if ((c & 0xF8) == 0xF0) { - return c & 0x07; - } - CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - void hexEscapeChar(std::ostream& os, unsigned char c) { - os << "\\x" - << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast(c); - } - -} // anonymous namespace - - XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) - : m_str( str ), - m_forWhat( forWhat ) - {} - - void XmlEncode::encodeTo( std::ostream& os ) const { - // Apostrophe escaping not necessary if we always use " to write attributes - // (see: http://www.w3.org/TR/xml/#syntax) - - for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - uchar c = m_str[idx]; - switch (c) { - case '<': os << "<"; break; - case '&': os << "&"; break; - - case '>': - // See: http://www.w3.org/TR/xml/#syntax - if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') - os << ">"; - else - os << c; - break; - - case '\"': - if (m_forWhat == ForAttributes) - os << """; - else - os << c; - break; - - default: - // Check for control characters and invalid utf-8 - - // Escape control characters in standard ascii - // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { - hexEscapeChar(os, c); - break; - } - - // Plain ASCII: Write it to stream - if (c < 0x7F) { - os << c; - break; - } - - // UTF-8 territory - // Check if the encoding is valid and if it is not, hex escape bytes. - // Important: We do not check the exact decoded values for validity, only the encoding format - // First check that this bytes is a valid lead byte: - // This means that it is not encoded as 1111 1XXX - // Or as 10XX XXXX - if (c < 0xC0 || - c >= 0xF8) { - hexEscapeChar(os, c); - break; - } - - auto encBytes = trailingBytes(c); - // Are there enough bytes left to avoid accessing out-of-bounds memory? - if (idx + encBytes - 1 >= m_str.size()) { - hexEscapeChar(os, c); - break; - } - // The header is valid, check data - // The next encBytes bytes must together be a valid utf-8 - // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) - bool valid = true; - uint32_t value = headerValue(c); - for (std::size_t n = 1; n < encBytes; ++n) { - uchar nc = m_str[idx + n]; - valid &= ((nc & 0xC0) == 0x80); - value = (value << 6) | (nc & 0x3F); - } - - if ( - // Wrong bit pattern of following bytes - (!valid) || - // Overlong encodings - (value < 0x80) || - (0x80 <= value && value < 0x800 && encBytes > 2) || - (0x800 < value && value < 0x10000 && encBytes > 3) || - // Encoded value out of range - (value >= 0x110000) - ) { - hexEscapeChar(os, c); - break; - } - - // If we got here, this is in fact a valid(ish) utf-8 sequence - for (std::size_t n = 0; n < encBytes; ++n) { - os << m_str[idx + n]; - } - idx += encBytes - 1; - break; - } - } - } - - std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; - } - - XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} - - XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept - : m_writer( other.m_writer ){ - other.m_writer = nullptr; - } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { - if ( m_writer ) { - m_writer->endElement(); - } - m_writer = other.m_writer; - other.m_writer = nullptr; - return *this; - } - - XmlWriter::ScopedElement::~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } - - XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { - m_writer->writeText( text, indent ); - return *this; - } - - XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) - { - writeDeclaration(); - } - - XmlWriter::~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } - - XmlWriter& XmlWriter::startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } - - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } - - XmlWriter& XmlWriter::endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << ""; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; - } - - XmlWriter& XmlWriter::writeComment( std::string const& text ) { - ensureTagClosed(); - m_os << m_indent << ""; - m_needsNewline = true; - return *this; - } - - void XmlWriter::writeStylesheetRef( std::string const& url ) { - m_os << "\n"; - } - - XmlWriter& XmlWriter::writeBlankLine() { - ensureTagClosed(); - m_os << '\n'; - return *this; - } - - void XmlWriter::ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } - - void XmlWriter::writeDeclaration() { - m_os << "\n"; - } - - void XmlWriter::newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } - } -} -// end catch_xmlwriter.cpp -// start catch_reporter_bases.cpp - -#include -#include -#include -#include -#include - -namespace Catch { - void prepareExpandedExpression(AssertionResult& result) { - result.getExpandedExpression(); - } - - // Because formatting using c++ streams is stateful, drop down to C is required - // Alternatively we could use stringstream, but its performance is... not good. - std::string getFormattedDuration( double duration ) { - // Max exponent + 1 is required to represent the whole part - // + 1 for decimal point - // + 3 for the 3 decimal places - // + 1 for null terminator - const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; - char buffer[maxDoubleSize]; - - // Save previous errno, to prevent sprintf from overwriting it - ErrnoGuard guard; -#ifdef _MSC_VER - sprintf_s(buffer, "%.3f", duration); -#else - sprintf(buffer, "%.3f", duration); -#endif - return std::string(buffer); - } - - TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) - :StreamingReporterBase(_config) {} - - void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} - - bool TestEventListenerBase::assertionEnded(AssertionStats const &) { - return false; - } - -} // end namespace Catch -// end catch_reporter_bases.cpp -// start catch_reporter_compact.cpp - -namespace { - -#ifdef CATCH_PLATFORM_MAC - const char* failedString() { return "FAILED"; } - const char* passedString() { return "PASSED"; } -#else - const char* failedString() { return "failed"; } - const char* passedString() { return "passed"; } -#endif - - // Colour::LightGrey - Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } - - std::string bothOrAll( std::size_t count ) { - return count == 1 ? std::string() : - count == 2 ? "both " : "all " ; - } - -} // anon namespace - -namespace Catch { -namespace { -// Colour, message variants: -// - white: No tests ran. -// - red: Failed [both/all] N test cases, failed [both/all] M assertions. -// - white: Passed [both/all] N test cases (no assertions). -// - red: Failed N tests cases, failed M assertions. -// - green: Passed [both/all] N tests cases with M assertions. -void printTotals(std::ostream& out, const Totals& totals) { - if (totals.testCases.total() == 0) { - out << "No tests ran."; - } else if (totals.testCases.failed == totals.testCases.total()) { - Colour colour(Colour::ResultError); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll(totals.assertions.failed) : std::string(); - out << - "Failed " << bothOrAll(totals.testCases.failed) - << pluralise(totals.testCases.failed, "test case") << ", " - "failed " << qualify_assertions_failed << - pluralise(totals.assertions.failed, "assertion") << '.'; - } else if (totals.assertions.total() == 0) { - out << - "Passed " << bothOrAll(totals.testCases.total()) - << pluralise(totals.testCases.total(), "test case") - << " (no assertions)."; - } else if (totals.assertions.failed) { - Colour colour(Colour::ResultError); - out << - "Failed " << pluralise(totals.testCases.failed, "test case") << ", " - "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; - } else { - Colour colour(Colour::ResultSuccess); - out << - "Passed " << bothOrAll(totals.testCases.passed) - << pluralise(totals.testCases.passed, "test case") << - " with " << pluralise(totals.assertions.passed, "assertion") << '.'; - } -} - -// Implementation of CompactReporter formatting -class AssertionPrinter { -public: - AssertionPrinter& operator= (AssertionPrinter const&) = delete; - AssertionPrinter(AssertionPrinter const&) = delete; - AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) - : stream(_stream) - , result(_stats.assertionResult) - , messages(_stats.infoMessages) - , itMessage(_stats.infoMessages.begin()) - , printInfoMessages(_printInfoMessages) {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch (result.getResultType()) { - case ResultWas::Ok: - printResultType(Colour::ResultSuccess, passedString()); - printOriginalExpression(); - printReconstructedExpression(); - if (!result.hasExpression()) - printRemainingMessages(Colour::None); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if (result.isOk()) - printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); - else - printResultType(Colour::Error, failedString()); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType(Colour::Error, failedString()); - printIssue("unexpected exception with message:"); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType(Colour::Error, failedString()); - printIssue("fatal error condition with message:"); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType(Colour::Error, failedString()); - printIssue("expected exception, got none"); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType(Colour::None, "info"); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType(Colour::None, "warning"); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType(Colour::Error, failedString()); - printIssue("explicitly"); - printRemainingMessages(Colour::None); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType(Colour::Error, "** internal error **"); - break; - } - } - -private: - void printSourceInfo() const { - Colour colourGuard(Colour::FileName); - stream << result.getSourceInfo() << ':'; - } - - void printResultType(Colour::Code colour, std::string const& passOrFail) const { - if (!passOrFail.empty()) { - { - Colour colourGuard(colour); - stream << ' ' << passOrFail; - } - stream << ':'; - } - } - - void printIssue(std::string const& issue) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if (result.hasExpression()) { - stream << ';'; - { - Colour colour(dimColour()); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if (result.hasExpression()) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if (result.hasExpandedExpression()) { - { - Colour colour(dimColour()); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if (itMessage != messages.end()) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages(Colour::Code colour = dimColour()) { - if (itMessage == messages.end()) - return; - - // using messages.end() directly yields (or auto) compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast(std::distance(itMessage, itEnd)); - - { - Colour colourGuard(colour); - stream << " with " << pluralise(N, "message") << ':'; - } - - for (; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if (printInfoMessages || itMessage->type != ResultWas::Info) { - stream << " '" << itMessage->message << '\''; - if (++itMessage != itEnd) { - Colour colourGuard(dimColour()); - stream << " and"; - } - } - } - } - -private: - std::ostream& stream; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; -}; - -} // anon namespace - - std::string CompactReporter::getDescription() { - return "Reports test results on a single line, suitable for IDEs"; - } - - ReporterPreferences CompactReporter::getPreferences() const { - return m_reporterPrefs; - } - - void CompactReporter::noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << '\'' << std::endl; - } - - void CompactReporter::assertionStarting( AssertionInfo const& ) {} - - bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool printInfoMessages = true; - - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } - - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); - - stream << std::endl; - return true; - } - - void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - } - - void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { - printTotals( stream, _testRunStats.totals ); - stream << '\n' << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - CompactReporter::~CompactReporter() {} - - CATCH_REGISTER_REPORTER( "compact", CompactReporter ) - -} // end namespace Catch -// end catch_reporter_compact.cpp -// start catch_reporter_console.cpp - -#include -#include - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif - -namespace Catch { - -namespace { - -// Formatter impl for ConsoleReporter -class ConsoleAssertionPrinter { -public: - ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; - ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; - ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) - : stream(_stream), - stats(_stats), - result(_stats.assertionResult), - colour(Colour::None), - message(result.getMessage()), - messages(_stats.infoMessages), - printInfoMessages(_printInfoMessages) { - switch (result.getResultType()) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"; - //if( result.hasMessage() ) - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; - break; - case ResultWas::ExpressionFailed: - if (result.isOk()) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"; - } else { - colour = Colour::Error; - passOrFail = "FAILED"; - } - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to a fatal error condition"; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "because no exception was thrown where one was expected"; - break; - case ResultWas::Info: - messageLabel = "info"; - break; - case ResultWas::Warning: - messageLabel = "warning"; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"; - colour = Colour::Error; - if (_stats.infoMessages.size() == 1) - messageLabel = "explicitly with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "explicitly with messages"; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"; - colour = Colour::Error; - break; - } - } - - void print() const { - printSourceInfo(); - if (stats.totals.assertions.total() > 0) { - if (result.isOk()) - stream << '\n'; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } else { - stream << '\n'; - } - printMessage(); - } - -private: - void printResultType() const { - if (!passOrFail.empty()) { - Colour colourGuard(colour); - stream << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if (result.hasExpression()) { - Colour colourGuard(Colour::OriginalExpression); - stream << " "; - stream << result.getExpressionInMacro(); - stream << '\n'; - } - } - void printReconstructedExpression() const { - if (result.hasExpandedExpression()) { - stream << "with expansion:\n"; - Colour colourGuard(Colour::ReconstructedExpression); - stream << Column(result.getExpandedExpression()).indent(2) << '\n'; - } - } - void printMessage() const { - if (!messageLabel.empty()) - stream << messageLabel << ':' << '\n'; - for (auto const& msg : messages) { - // If this assertion is a warning ignore any INFO messages - if (printInfoMessages || msg.type != ResultWas::Info) - stream << Column(msg.message).indent(2) << '\n'; - } - } - void printSourceInfo() const { - Colour colourGuard(Colour::FileName); - stream << result.getSourceInfo() << ": "; - } - - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; - bool printInfoMessages; -}; - -std::size_t makeRatio(std::size_t number, std::size_t total) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; - return (ratio == 0 && number > 0) ? 1 : ratio; -} - -std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { - if (i > j && i > k) - return i; - else if (j > k) - return j; - else - return k; -} - -struct ColumnInfo { - enum Justification { Left, Right }; - std::string name; - int width; - Justification justification; -}; -struct ColumnBreak {}; -struct RowBreak {}; - -class Duration { - enum class Unit { - Auto, - Nanoseconds, - Microseconds, - Milliseconds, - Seconds, - Minutes - }; - static const uint64_t s_nanosecondsInAMicrosecond = 1000; - static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; - static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; - static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; - - uint64_t m_inNanoseconds; - Unit m_units; - -public: - explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) - : m_inNanoseconds(inNanoseconds), - m_units(units) { - if (m_units == Unit::Auto) { - if (m_inNanoseconds < s_nanosecondsInAMicrosecond) - m_units = Unit::Nanoseconds; - else if (m_inNanoseconds < s_nanosecondsInAMillisecond) - m_units = Unit::Microseconds; - else if (m_inNanoseconds < s_nanosecondsInASecond) - m_units = Unit::Milliseconds; - else if (m_inNanoseconds < s_nanosecondsInAMinute) - m_units = Unit::Seconds; - else - m_units = Unit::Minutes; - } - - } - - auto value() const -> double { - switch (m_units) { - case Unit::Microseconds: - return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); - case Unit::Milliseconds: - return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); - case Unit::Seconds: - return m_inNanoseconds / static_cast(s_nanosecondsInASecond); - case Unit::Minutes: - return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); - default: - return static_cast(m_inNanoseconds); - } - } - auto unitsAsString() const -> std::string { - switch (m_units) { - case Unit::Nanoseconds: - return "ns"; - case Unit::Microseconds: - return "µs"; - case Unit::Milliseconds: - return "ms"; - case Unit::Seconds: - return "s"; - case Unit::Minutes: - return "m"; - default: - return "** internal error **"; - } - - } - friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { - return os << duration.value() << " " << duration.unitsAsString(); - } -}; -} // end anon namespace - -class TablePrinter { - std::ostream& m_os; - std::vector m_columnInfos; - std::ostringstream m_oss; - int m_currentColumn = -1; - bool m_isOpen = false; - -public: - TablePrinter( std::ostream& os, std::vector columnInfos ) - : m_os( os ), - m_columnInfos( std::move( columnInfos ) ) {} - - auto columnInfos() const -> std::vector const& { - return m_columnInfos; - } - - void open() { - if (!m_isOpen) { - m_isOpen = true; - *this << RowBreak(); - for (auto const& info : m_columnInfos) - *this << info.name << ColumnBreak(); - *this << RowBreak(); - m_os << Catch::getLineOfChars<'-'>() << "\n"; - } - } - void close() { - if (m_isOpen) { - *this << RowBreak(); - m_os << std::endl; - m_isOpen = false; - } - } - - template - friend TablePrinter& operator << (TablePrinter& tp, T const& value) { - tp.m_oss << value; - return tp; - } - - friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { - auto colStr = tp.m_oss.str(); - // This takes account of utf8 encodings - auto strSize = Catch::StringRef(colStr).numberOfCharacters(); - tp.m_oss.str(""); - tp.open(); - if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { - tp.m_currentColumn = -1; - tp.m_os << "\n"; - } - tp.m_currentColumn++; - - auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; - auto padding = (strSize + 2 < static_cast(colInfo.width)) - ? std::string(colInfo.width - (strSize + 2), ' ') - : std::string(); - if (colInfo.justification == ColumnInfo::Left) - tp.m_os << colStr << padding << " "; - else - tp.m_os << padding << colStr << " "; - return tp; - } - - friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { - if (tp.m_currentColumn > 0) { - tp.m_os << "\n"; - tp.m_currentColumn = -1; - } - return tp; - } -}; - -ConsoleReporter::ConsoleReporter(ReporterConfig const& config) - : StreamingReporterBase(config), - m_tablePrinter(new TablePrinter(config.stream(), - { - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, - { "iters", 8, ColumnInfo::Right }, - { "elapsed ns", 14, ColumnInfo::Right }, - { "average", 14, ColumnInfo::Right } - })) {} -ConsoleReporter::~ConsoleReporter() = default; - -std::string ConsoleReporter::getDescription() { - return "Reports test results as plain lines of text"; -} - -void ConsoleReporter::noMatchingTestCases(std::string const& spec) { - stream << "No test cases matched '" << spec << '\'' << std::endl; -} - -void ConsoleReporter::assertionStarting(AssertionInfo const&) {} - -bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - // Drop out if result was successful but we're not printing them. - if (!includeResults && result.getResultType() != ResultWas::Warning) - return false; - - lazyPrint(); - - ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); - printer.print(); - stream << std::endl; - return true; -} - -void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting(_sectionInfo); -} -void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { - m_tablePrinter->close(); - if (_sectionStats.missingAssertions) { - lazyPrint(); - Colour colour(Colour::ResultError); - if (m_sectionStack.size() > 1) - stream << "\nNo assertions in section"; - else - stream << "\nNo assertions in test case"; - stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; - } - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - if (m_headerPrinted) { - m_headerPrinted = false; - } - StreamingReporterBase::sectionEnded(_sectionStats); -} - -void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { - lazyPrintWithoutClosingBenchmarkTable(); - - auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); - - bool firstLine = true; - for (auto line : nameCol) { - if (!firstLine) - (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; - - (*m_tablePrinter) << line << ColumnBreak(); - } -} -void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { - Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); - (*m_tablePrinter) - << stats.iterations << ColumnBreak() - << stats.elapsedTimeInNanoseconds << ColumnBreak() - << average << ColumnBreak(); -} - -void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { - m_tablePrinter->close(); - StreamingReporterBase::testCaseEnded(_testCaseStats); - m_headerPrinted = false; -} -void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { - if (currentGroupInfo.used) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals(_testGroupStats.totals); - stream << '\n' << std::endl; - } - StreamingReporterBase::testGroupEnded(_testGroupStats); -} -void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { - printTotalsDivider(_testRunStats.totals); - printTotals(_testRunStats.totals); - stream << std::endl; - StreamingReporterBase::testRunEnded(_testRunStats); -} - -void ConsoleReporter::lazyPrint() { - - m_tablePrinter->close(); - lazyPrintWithoutClosingBenchmarkTable(); -} - -void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { - - if (!currentTestRunInfo.used) - lazyPrintRunInfo(); - if (!currentGroupInfo.used) - lazyPrintGroupInfo(); - - if (!m_headerPrinted) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } -} -void ConsoleReporter::lazyPrintRunInfo() { - stream << '\n' << getLineOfChars<'~'>() << '\n'; - Colour colour(Colour::SecondaryText); - stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion() << " host application.\n" - << "Run with -? for options\n\n"; - - if (m_config->rngSeed() != 0) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - - currentTestRunInfo.used = true; -} -void ConsoleReporter::lazyPrintGroupInfo() { - if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { - printClosedHeader("Group: " + currentGroupInfo->name); - currentGroupInfo.used = true; - } -} -void ConsoleReporter::printTestCaseAndSectionHeader() { - assert(!m_sectionStack.empty()); - printOpenHeader(currentTestCaseInfo->name); - - if (m_sectionStack.size() > 1) { - Colour colourGuard(Colour::Headers); - - auto - it = m_sectionStack.begin() + 1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for (; it != itEnd; ++it) - printHeaderString(it->name, 2); - } - - SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - - if (!lineInfo.empty()) { - stream << getLineOfChars<'-'>() << '\n'; - Colour colourGuard(Colour::FileName); - stream << lineInfo << '\n'; - } - stream << getLineOfChars<'.'>() << '\n' << std::endl; -} - -void ConsoleReporter::printClosedHeader(std::string const& _name) { - printOpenHeader(_name); - stream << getLineOfChars<'.'>() << '\n'; -} -void ConsoleReporter::printOpenHeader(std::string const& _name) { - stream << getLineOfChars<'-'>() << '\n'; - { - Colour colourGuard(Colour::Headers); - printHeaderString(_name); - } -} - -// if string has a : in first line will set indent to follow it on -// subsequent lines -void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { - std::size_t i = _string.find(": "); - if (i != std::string::npos) - i += 2; - else - i = 0; - stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; -} - -struct SummaryColumn { - - SummaryColumn( std::string _label, Colour::Code _colour ) - : label( std::move( _label ) ), - colour( _colour ) {} - SummaryColumn addRow( std::size_t count ) { - ReusableStringStream rss; - rss << count; - std::string row = rss.str(); - for (auto& oldRow : rows) { - while (oldRow.size() < row.size()) - oldRow = ' ' + oldRow; - while (oldRow.size() > row.size()) - row = ' ' + row; - } - rows.push_back(row); - return *this; - } - - std::string label; - Colour::Code colour; - std::vector rows; - -}; - -void ConsoleReporter::printTotals( Totals const& totals ) { - if (totals.testCases.total() == 0) { - stream << Colour(Colour::Warning) << "No tests ran\n"; - } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { - stream << Colour(Colour::ResultSuccess) << "All tests passed"; - stream << " (" - << pluralise(totals.assertions.passed, "assertion") << " in " - << pluralise(totals.testCases.passed, "test case") << ')' - << '\n'; - } else { - - std::vector columns; - columns.push_back(SummaryColumn("", Colour::None) - .addRow(totals.testCases.total()) - .addRow(totals.assertions.total())); - columns.push_back(SummaryColumn("passed", Colour::Success) - .addRow(totals.testCases.passed) - .addRow(totals.assertions.passed)); - columns.push_back(SummaryColumn("failed", Colour::ResultError) - .addRow(totals.testCases.failed) - .addRow(totals.assertions.failed)); - columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) - .addRow(totals.testCases.failedButOk) - .addRow(totals.assertions.failedButOk)); - - printSummaryRow("test cases", columns, 0); - printSummaryRow("assertions", columns, 1); - } -} -void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { - for (auto col : cols) { - std::string value = col.rows[row]; - if (col.label.empty()) { - stream << label << ": "; - if (value != "0") - stream << value; - else - stream << Colour(Colour::Warning) << "- none -"; - } else if (value != "0") { - stream << Colour(Colour::LightGrey) << " | "; - stream << Colour(col.colour) - << value << ' ' << col.label; - } - } - stream << '\n'; -} - -void ConsoleReporter::printTotalsDivider(Totals const& totals) { - if (totals.testCases.total() > 0) { - std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); - std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); - std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); - while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)++; - while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)--; - - stream << Colour(Colour::Error) << std::string(failedRatio, '='); - stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); - if (totals.testCases.allPassed()) - stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); - else - stream << Colour(Colour::Success) << std::string(passedRatio, '='); - } else { - stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); - } - stream << '\n'; -} -void ConsoleReporter::printSummaryDivider() { - stream << getLineOfChars<'-'>() << '\n'; -} - -CATCH_REGISTER_REPORTER("console", ConsoleReporter) - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -// end catch_reporter_console.cpp -// start catch_reporter_junit.cpp - -#include -#include -#include -#include - -namespace Catch { - - namespace { - std::string getCurrentTimestamp() { - // Beware, this is not reentrant because of backward compatibility issues - // Also, UTC only, again because of backward compatibility (%z is C++11) - time_t rawtime; - std::time(&rawtime); - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &rawtime); -#else - std::tm* timeInfo; - timeInfo = std::gmtime(&rawtime); -#endif - - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp); - } - - std::string fileNameTag(const std::vector &tags) { - auto it = std::find_if(begin(tags), - end(tags), - [] (std::string const& tag) {return tag.front() == '#'; }); - if (it != tags.end()) - return it->substr(1); - return std::string(); - } - } // anonymous namespace - - JunitReporter::JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = true; - m_reporterPrefs.shouldReportAllAssertions = true; - } - - JunitReporter::~JunitReporter() {} - - std::string JunitReporter::getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } - - void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} - - void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } - - void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { - suiteTimer.start(); - stdOutForSuite.clear(); - stdErrForSuite.clear(); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } - - void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { - m_okToFail = testCaseInfo.okToFail(); - } - - bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } - - void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - stdOutForSuite += testCaseStats.stdOut; - stdErrForSuite += testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } - - void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } - - void JunitReporter::testRunEndedCumulative() { - xml.endElement(); - } - - void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", getCurrentTimestamp() ); - - // Write test cases - for( auto const& child : groupNode.children ) - writeTestCase( *child ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); - } - - void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); - - std::string className = stats.testInfo.className; - - if( className.empty() ) { - className = fileNameTag(stats.testInfo.tags); - if ( className.empty() ) - className = "global"; - } - - if ( !m_config->name().empty() ) - className = m_config->name() + "." + className; - - writeSection( className, "", rootSection ); - } - - void JunitReporter::writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); - - writeAssertions( sectionNode ); - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); - } - for( auto const& childNode : sectionNode.childSections ) - if( className.empty() ) - writeSection( name, "", *childNode ); - else - writeSection( className, name, *childNode ); - } - - void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { - for( auto const& assertion : sectionNode.assertions ) - writeAssertion( assertion ); - } - - void JunitReporter::writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); - - ReusableStringStream rss; - if( !result.getMessage().empty() ) - rss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - rss << msg.message << '\n'; - - rss << "at " << result.getSourceInfo(); - xml.writeText( rss.str(), false ); - } - } - - CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - -} // end namespace Catch -// end catch_reporter_junit.cpp -// start catch_reporter_listening.cpp - -#include - -namespace Catch { - - ListeningReporter::ListeningReporter() { - // We will assume that listeners will always want all assertions - m_preferences.shouldReportAllAssertions = true; - } - - void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { - m_listeners.push_back( std::move( listener ) ); - } - - void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { - assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); - m_reporter = std::move( reporter ); - m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; - } - - ReporterPreferences ListeningReporter::getPreferences() const { - return m_preferences; - } - - std::set ListeningReporter::getSupportedVerbosities() { - return std::set{ }; - } - - void ListeningReporter::noMatchingTestCases( std::string const& spec ) { - for ( auto const& listener : m_listeners ) { - listener->noMatchingTestCases( spec ); - } - m_reporter->noMatchingTestCases( spec ); - } - - void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { - for ( auto const& listener : m_listeners ) { - listener->benchmarkStarting( benchmarkInfo ); - } - m_reporter->benchmarkStarting( benchmarkInfo ); - } - void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { - for ( auto const& listener : m_listeners ) { - listener->benchmarkEnded( benchmarkStats ); - } - m_reporter->benchmarkEnded( benchmarkStats ); - } - - void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { - for ( auto const& listener : m_listeners ) { - listener->testRunStarting( testRunInfo ); - } - m_reporter->testRunStarting( testRunInfo ); - } - - void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { - for ( auto const& listener : m_listeners ) { - listener->testGroupStarting( groupInfo ); - } - m_reporter->testGroupStarting( groupInfo ); - } - - void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { - for ( auto const& listener : m_listeners ) { - listener->testCaseStarting( testInfo ); - } - m_reporter->testCaseStarting( testInfo ); - } - - void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { - for ( auto const& listener : m_listeners ) { - listener->sectionStarting( sectionInfo ); - } - m_reporter->sectionStarting( sectionInfo ); - } - - void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { - for ( auto const& listener : m_listeners ) { - listener->assertionStarting( assertionInfo ); - } - m_reporter->assertionStarting( assertionInfo ); - } - - // The return value indicates if the messages buffer should be cleared: - bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { - for( auto const& listener : m_listeners ) { - static_cast( listener->assertionEnded( assertionStats ) ); - } - return m_reporter->assertionEnded( assertionStats ); - } - - void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { - for ( auto const& listener : m_listeners ) { - listener->sectionEnded( sectionStats ); - } - m_reporter->sectionEnded( sectionStats ); - } - - void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - for ( auto const& listener : m_listeners ) { - listener->testCaseEnded( testCaseStats ); - } - m_reporter->testCaseEnded( testCaseStats ); - } - - void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { - for ( auto const& listener : m_listeners ) { - listener->testGroupEnded( testGroupStats ); - } - m_reporter->testGroupEnded( testGroupStats ); - } - - void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { - for ( auto const& listener : m_listeners ) { - listener->testRunEnded( testRunStats ); - } - m_reporter->testRunEnded( testRunStats ); - } - - void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { - for ( auto const& listener : m_listeners ) { - listener->skipTest( testInfo ); - } - m_reporter->skipTest( testInfo ); - } - - bool ListeningReporter::isMulti() const { - return true; - } - -} // end namespace Catch -// end catch_reporter_listening.cpp -// start catch_reporter_xml.cpp - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif - -namespace Catch { - XmlReporter::XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()) - { - m_reporterPrefs.shouldRedirectStdOut = true; - m_reporterPrefs.shouldReportAllAssertions = true; - } - - XmlReporter::~XmlReporter() = default; - - std::string XmlReporter::getDescription() { - return "Reports test results as an XML document"; - } - - std::string XmlReporter::getStylesheetRef() const { - return std::string(); - } - - void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); - } - - void XmlReporter::noMatchingTestCases( std::string const& s ) { - StreamingReporterBase::noMatchingTestCases( s ); - } - - void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } - - void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } - - void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString() ); - - writeSourceInfo( testInfo.lineInfo ); - - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - m_xml.ensureTagClosed(); - } - - void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); - } - } - - void XmlReporter::assertionStarting( AssertionInfo const& ) { } - - bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { - - AssertionResult const& result = assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - if( includeResults || result.getResultType() == ResultWas::Warning ) { - // Print any info messages in tags. - for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info && includeResults ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); - } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); - } - } - } - - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; - - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); - - writeSourceInfo( result.getSourceInfo() ); - - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } - - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; - } - - if( result.hasExpression() ) - m_xml.endElement(); - - return true; - } - - void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - - m_xml.endElement(); - } - } - - void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); - - m_xml.endElement(); - } - - void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - CATCH_REGISTER_REPORTER( "xml", XmlReporter ) - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -// end catch_reporter_xml.cpp - -namespace Catch { - LeakDetector leakDetector; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_impl.hpp -#endif - -#ifdef CATCH_CONFIG_MAIN -// start catch_default_main.hpp - -#ifndef __OBJC__ - -#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) -// Standard C/C++ Win32 Unicode wmain entry point -extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { -#else -// Standard C/C++ main entry point -int main (int argc, char * argv[]) { -#endif - - return Catch::Session().run( argc, argv ); -} - -#else // __OBJC__ - -// Objective-C entry point -int main (int argc, char * const argv[]) { -#if !CATCH_ARC_ENABLED - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; -#endif - - Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char**)argv ); - -#if !CATCH_ARC_ENABLED - [pool drain]; -#endif - - return result; -} - -#endif // __OBJC__ - -// end catch_default_main.hpp -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) - -#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED -# undef CLARA_CONFIG_MAIN -#endif - -#if !defined(CATCH_CONFIG_DISABLE) -////// -// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ -#ifdef CATCH_CONFIG_PREFIX_ALL - -#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - -#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) -#endif// CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - -#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - -#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) - -#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) -#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) - -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) -#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) -#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) -#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) -#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) -#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() - -// "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) -#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) -#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) -#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) -#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) -#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) - -// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required -#else - -#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - -#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - -#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - -#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) - -#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) -#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) - -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) -#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) -#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) -#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) -#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) -#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() - -#endif - -#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) - -// "BDD-style" convenience wrappers -#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) - -#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) -#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) -#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) -#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) -#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) -#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) - -using Catch::Detail::Approx; - -#else // CATCH_CONFIG_DISABLE - -////// -// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ -#ifdef CATCH_CONFIG_PREFIX_ALL - -#define CATCH_REQUIRE( ... ) (void)(0) -#define CATCH_REQUIRE_FALSE( ... ) (void)(0) - -#define CATCH_REQUIRE_THROWS( ... ) (void)(0) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif// CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) - -#define CATCH_CHECK( ... ) (void)(0) -#define CATCH_CHECK_FALSE( ... ) (void)(0) -#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) -#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) -#define CATCH_CHECK_NOFAIL( ... ) (void)(0) - -#define CATCH_CHECK_THROWS( ... ) (void)(0) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_CHECK_NOTHROW( ... ) (void)(0) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) - -#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define CATCH_INFO( msg ) (void)(0) -#define CATCH_WARN( msg ) (void)(0) -#define CATCH_CAPTURE( msg ) (void)(0) - -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_METHOD_AS_TEST_CASE( method, ... ) -#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) -#define CATCH_SECTION( ... ) -#define CATCH_DYNAMIC_SECTION( ... ) -#define CATCH_FAIL( ... ) (void)(0) -#define CATCH_FAIL_CHECK( ... ) (void)(0) -#define CATCH_SUCCEED( ... ) (void)(0) - -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) - -// "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) -#define CATCH_GIVEN( desc ) -#define CATCH_AND_GIVEN( desc ) -#define CATCH_WHEN( desc ) -#define CATCH_AND_WHEN( desc ) -#define CATCH_THEN( desc ) -#define CATCH_AND_THEN( desc ) - -// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required -#else - -#define REQUIRE( ... ) (void)(0) -#define REQUIRE_FALSE( ... ) (void)(0) - -#define REQUIRE_THROWS( ... ) (void)(0) -#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) -#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define REQUIRE_NOTHROW( ... ) (void)(0) - -#define CHECK( ... ) (void)(0) -#define CHECK_FALSE( ... ) (void)(0) -#define CHECKED_IF( ... ) if (__VA_ARGS__) -#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) -#define CHECK_NOFAIL( ... ) (void)(0) - -#define CHECK_THROWS( ... ) (void)(0) -#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) -#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CHECK_NOTHROW( ... ) (void)(0) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THAT( arg, matcher ) (void)(0) - -#define REQUIRE_THAT( arg, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define INFO( msg ) (void)(0) -#define WARN( msg ) (void)(0) -#define CAPTURE( msg ) (void)(0) - -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define METHOD_AS_TEST_CASE( method, ... ) -#define REGISTER_TEST_CASE( Function, ... ) (void)(0) -#define SECTION( ... ) -#define DYNAMIC_SECTION( ... ) -#define FAIL( ... ) (void)(0) -#define FAIL_CHECK( ... ) (void)(0) -#define SUCCEED( ... ) (void)(0) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) - -#endif - -#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) - -// "BDD-style" convenience wrappers -#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) - -#define GIVEN( desc ) -#define AND_GIVEN( desc ) -#define WHEN( desc ) -#define AND_WHEN( desc ) -#define THEN( desc ) -#define AND_THEN( desc ) - -using Catch::Detail::Approx; - -#endif - -#endif // ! CATCH_CONFIG_IMPL_ONLY - -// start catch_reenable_warnings.h - - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(pop) -# else -# pragma clang diagnostic pop -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - -// end catch_reenable_warnings.h -// end catch.hpp -#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - diff --git a/vendor/FileSystem/test/cmake/ParseAndAddCatchTests.cmake b/vendor/FileSystem/test/cmake/ParseAndAddCatchTests.cmake deleted file mode 100644 index 5e89cb76..00000000 --- a/vendor/FileSystem/test/cmake/ParseAndAddCatchTests.cmake +++ /dev/null @@ -1,230 +0,0 @@ -#==================================================================================================# -# supported macros # -# - TEST_CASE, # -# - SCENARIO, # -# - TEST_CASE_METHOD, # -# - CATCH_TEST_CASE, # -# - CATCH_SCENARIO, # -# - CATCH_TEST_CASE_METHOD. # -# # -# Usage # -# 1. make sure this module is in the path or add this otherwise: # -# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") # -# 2. make sure that you've enabled testing option for the project by the call: # -# enable_testing() # -# 3. add the lines to the script for testing target (sample CMakeLists.txt): # -# project(testing_target) # -# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") # -# enable_testing() # -# # -# find_path(CATCH_INCLUDE_DIR "catch.hpp") # -# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) # -# # -# file(GLOB SOURCE_FILES "*.cpp") # -# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) # -# # -# include(ParseAndAddCatchTests) # -# ParseAndAddCatchTests(${PROJECT_NAME}) # -# # -# The following variables affect the behavior of the script: # -# # -# PARSE_CATCH_TESTS_VERBOSE (Default OFF) # -# -- enables debug messages # -# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) # -# -- excludes tests marked with [!hide], [.] or [.foo] tags # -# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) # -# -- adds fixture class name to the test name # -# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) # -# -- adds cmake target name to the test name # -# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) # -# -- causes CMake to rerun when file with tests changes so that new tests will be discovered # -# # -# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way # -# a test should be run. For instance to use test MPI, one can write # -# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) # -# just before calling this ParseAndAddCatchTests function # -# # -# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test # -# command. For example, to include successful tests in the output, one can write # -# set(AdditionalCatchParameters --success) # -# # -# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source # -# file in the target is set, and contains the list of the tests extracted from that target, or # -# from that file. This is useful, for example to add further labels or properties to the tests. # -# # -#==================================================================================================# - -if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8) - message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer") -endif() - -option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF) -option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF) -option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON) -option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON) -option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF) - -function(ParseAndAddCatchTests_PrintDebugMessage) - if(PARSE_CATCH_TESTS_VERBOSE) - message(STATUS "ParseAndAddCatchTests: ${ARGV}") - endif() -endfunction() - -# This removes the contents between -# - block comments (i.e. /* ... */) -# - full line comments (i.e. // ... ) -# contents have been read into '${CppCode}'. -# !keep partial line comments -function(ParseAndAddCatchTests_RemoveComments CppCode) - string(ASCII 2 CMakeBeginBlockComment) - string(ASCII 3 CMakeEndBlockComment) - string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}") - string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}") - string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}") - string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}") - - set(${CppCode} "${${CppCode}}" PARENT_SCOPE) -endfunction() - -# Worker function -function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget) - # If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file. - if(SourceFile MATCHES "\\\$") - ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.") - return() - endif() - # According to CMake docs EXISTS behavior is well-defined only for full paths. - get_filename_component(SourceFile ${SourceFile} ABSOLUTE) - if(NOT EXISTS ${SourceFile}) - message(WARNING "Cannot find source file: ${SourceFile}") - return() - endif() - ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}") - file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME) - - # Remove block and fullline comments - ParseAndAddCatchTests_RemoveComments(Contents) - - # Find definition of test names - string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}") - - if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests) - ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property") - set_property( - DIRECTORY - APPEND - PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile} - ) - endif() - - foreach(TestName ${Tests}) - # Strip newlines - string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}") - - # Get test type and fixture if applicable - string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}") - string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}") - string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}") - - # Get string parts of test definition - string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}") - - # Strip wrapping quotation marks - string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}") - string(REPLACE "\";\"" ";" TestStrings "${TestStrings}") - - # Validate that a test name and tags have been provided - list(LENGTH TestStrings TestStringsLength) - if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1) - message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}") - endif() - - # Assign name and tags - list(GET TestStrings 0 Name) - if("${TestType}" STREQUAL "SCENARIO") - set(Name "Scenario: ${Name}") - endif() - if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture ) - set(CTestName "${TestFixture}:${Name}") - else() - set(CTestName "${Name}") - endif() - if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME) - set(CTestName "${TestTarget}:${CTestName}") - endif() - # add target to labels to enable running all tests added from this target - set(Labels ${TestTarget}) - if(TestStringsLength EQUAL 2) - list(GET TestStrings 1 Tags) - string(TOLOWER "${Tags}" Tags) - # remove target from labels if the test is hidden - if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*") - list(REMOVE_ITEM Labels ${TestTarget}) - endif() - string(REPLACE "]" ";" Tags "${Tags}") - string(REPLACE "[" "" Tags "${Tags}") - else() - # unset tags variable from previous loop - unset(Tags) - endif() - - list(APPEND Labels ${Tags}) - - set(HiddenTagFound OFF) - foreach(label ${Labels}) - string(REGEX MATCH "^!hide|^\\." result ${label}) - if(result) - set(HiddenTagFound ON) - break() - endif(result) - endforeach(label) - if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9") - ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label") - else() - ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"") - if(Labels) - ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}") - endif() - - # Escape commas in the test spec - string(REPLACE "," "\\," Name ${Name}) - - # Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were neccessary, - # only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1 - if(NOT ${CMAKE_VERSION} VERSION_EQUAL "3.18") - set(CTestName "\"${CTestName}\"") - endif() - # Add the test and set its properties - add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $ ${Name} ${AdditionalCatchParameters}) - # Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead - if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8") - ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property") - set_tests_properties("${CTestName}" PROPERTIES DISABLED ON) - else() - set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran" - LABELS "${Labels}") - endif() - set_property( - TARGET ${TestTarget} - APPEND - PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}") - set_property( - SOURCE ${SourceFile} - APPEND - PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}") - endif() - - - endforeach() -endfunction() - -# entry point -function(ParseAndAddCatchTests TestTarget) - ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}") - get_target_property(SourceFiles ${TestTarget} SOURCES) - ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}") - foreach(SourceFile ${SourceFiles}) - ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget}) - endforeach() - ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}") -endfunction() diff --git a/vendor/FileSystem/test/exception.cpp b/vendor/FileSystem/test/exception.cpp deleted file mode 100644 index 8d8b7457..00000000 --- a/vendor/FileSystem/test/exception.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -int main() { - return 0; -} diff --git a/vendor/FileSystem/test/filesystem_test.cpp b/vendor/FileSystem/test/filesystem_test.cpp deleted file mode 100644 index 0eb5b81b..00000000 --- a/vendor/FileSystem/test/filesystem_test.cpp +++ /dev/null @@ -1,2952 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if (defined(WIN32) || defined(_WIN32)) && !defined(__GNUC__) -#define NOMINMAX 1 -#endif - -#ifdef USE_STD_FS -#include -namespace fs { -using namespace std::filesystem; -using ifstream = std::ifstream; -using ofstream = std::ofstream; -using fstream = std::fstream; -} // namespace fs -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#endif -#ifdef _MSC_VER -#define IS_WCHAR_PATH -#endif -#ifdef WIN32 -#define GHC_OS_WINDOWS -#endif -#else -#ifdef GHC_FILESYSTEM_FWD_TEST -#include -#else -#include -#endif -namespace fs { -using namespace ghc::filesystem; -using ifstream = ghc::filesystem::ifstream; -using ofstream = ghc::filesystem::ofstream; -using fstream = ghc::filesystem::fstream; -} // namespace fs -#endif - -#if defined(WIN32) || defined(_WIN32) -#include -#else -#include -#include -#include -#include -#include -#endif - -#ifndef GHC_FILESYSTEM_FWD_TEST -#define CATCH_CONFIG_MAIN -#endif -#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 -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// 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) -{ - using namespace std::chrono; - auto sctp = time_point_cast(tp - TP::clock::now() + system_clock::now()); - return system_clock::to_time_t(sctp); -} - -template -TP from_time_t(std::time_t t) -{ - using namespace std::chrono; - auto sctp = system_clock::from_time_t(t); - auto tp = time_point_cast(sctp - system_clock::now() + TP::clock::now()); - return tp; -} - -namespace Catch { -template <> -struct StringMaker -{ - static std::string convert(fs::path const& value) { return '"' + value.string() + '"'; } -}; - -template <> -struct StringMaker -{ - static std::string convert(fs::perms const& value) { return std::to_string(static_cast(value)); } -}; - -template <> -struct StringMaker -{ - static std::string convert(fs::file_status const& value) { - return std::string("[") + std::to_string(static_cast(value.type())) + "," + std::to_string(static_cast(value.permissions())) + "]"; - } -}; - -#ifdef __cpp_lib_char8_t -template <> -struct StringMaker -{ - static std::string convert(char8_t const& value) { return std::to_string(static_cast(value)); } -}; -#endif - -template <> -struct StringMaker -{ - static std::string convert(fs::file_time_type const& value) - { - std::time_t t = to_time_t(value); - std::tm* ptm = std::localtime(&t); - std::ostringstream os; - if (ptm) { - std::tm ttm = *ptm; - os << std::put_time(&ttm, "%Y-%m-%d %H:%M:%S"); - } - else { - os << "(invalid-time)"; - } - return os.str(); - } -}; -} // namespace Catch - -enum class TempOpt { none, change_path }; -class TemporaryDirectory -{ -public: - TemporaryDirectory(TempOpt opt = TempOpt::none) - { - static auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - static auto rng = std::bind(std::uniform_int_distribution(0, 35), std::mt19937(static_cast(seed) ^ static_cast(reinterpret_cast(&opt)))); - std::string filename; - do { - filename = "test_"; - for (int i = 0; i < 8; ++i) { - filename += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[rng()]; - } - _path = fs::canonical(fs::temp_directory_path()) / filename; - } while (fs::exists(_path)); - fs::create_directories(_path); - if (opt == TempOpt::change_path) { - _orig_dir = fs::current_path(); - fs::current_path(_path); - } - } - - ~TemporaryDirectory() - { - if (!_orig_dir.empty()) { - fs::current_path(_orig_dir); - } - fs::remove_all(_path); - } - - const fs::path& path() const { return _path; } - -private: - fs::path _path; - fs::path _orig_dir; -}; - -static void generateFile(const fs::path& pathname, int withSize = -1) -{ - fs::ofstream outfile(pathname); - if (withSize < 0) { - outfile << "Hello world!" << std::endl; - } - else { - outfile << std::string(size_t(withSize), '*'); - } -} - -#ifdef GHC_OS_WINDOWS -inline bool isWow64Proc() -{ - typedef BOOL(WINAPI * IsWow64Process_t)(HANDLE, PBOOL); - BOOL bIsWow64 = FALSE; - auto fnIsWow64Process = (IsWow64Process_t)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); - if (NULL != fnIsWow64Process) { - if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { - bIsWow64 = FALSE; - } - } - return bIsWow64 == TRUE; -} - -static bool is_symlink_creation_supported() -{ - bool result = true; - HKEY key; - REGSAM flags = KEY_READ; -#ifdef _WIN64 - flags |= KEY_WOW64_64KEY; -#elif defined(KEY_WOW64_64KEY) - if (isWow64Proc()) { - flags |= KEY_WOW64_64KEY; - } - else { - flags |= KEY_WOW64_32KEY; - } -#else - result = false; -#endif - if (result) { - auto err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", 0, flags, &key); - if (err == ERROR_SUCCESS) { - DWORD val = 0, size = sizeof(DWORD); - err = RegQueryValueExW(key, L"AllowDevelopmentWithoutDevLicense", 0, NULL, reinterpret_cast(&val), &size); - RegCloseKey(key); - if (err != ERROR_SUCCESS) { - result = false; - } - else { - result = (val != 0); - } - } - else { - result = false; - } - } - if (!result) { - std::clog << "Warning: Symlink creation not supported." << std::endl; - } - return result; -} -#else -static bool is_symlink_creation_supported() -{ - return true; -} -#endif - -static bool has_host_root_name_support() -{ - return fs::path("//host").has_root_name(); -} - -template -class TestAllocator -{ -public: - using value_type = T; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; - using difference_type = ptrdiff_t; - using size_type = size_t; - TestAllocator() noexcept {} - template - TestAllocator(TestAllocator const&) noexcept - { - } - value_type* allocate(std::size_t n) { return static_cast(::operator new(n * sizeof(value_type))); } - void deallocate(value_type* p, std::size_t) noexcept { ::operator delete(p); } - template - struct rebind { - typedef TestAllocator other; - }; -}; - -template -bool operator==(TestAllocator const&, TestAllocator const&) noexcept -{ - return true; -} - -template -bool operator!=(TestAllocator const& x, TestAllocator const& y) noexcept -{ - return !(x == y); -} - -TEST_CASE("Temporary Directory", "[fs.test.tempdir]") -{ - fs::path tempPath; - { - TemporaryDirectory t; - tempPath = t.path(); - REQUIRE(fs::exists(fs::path(t.path()))); - REQUIRE(fs::is_directory(t.path())); - } - REQUIRE(!fs::exists(tempPath)); -} - -#ifdef GHC_FILESYSTEM_VERSION -TEST_CASE("fs::detail::fromUtf8", "[filesystem][fs.detail.utf8]") -{ - CHECK(fs::detail::fromUtf8("foobar").length() == 6); - CHECK(fs::detail::fromUtf8("foobar") == L"foobar"); - CHECK(fs::detail::fromUtf8(u8"föobar").length() == 6); - CHECK(fs::detail::fromUtf8(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"); - -#ifdef GHC_RAISE_UNICODE_ERRORS - CHECK_THROWS_AS(fs::detail::fromUtf8(std::string("\xed\xa0\x80")), fs::filesystem_error); - CHECK_THROWS_AS(fs::detail::fromUtf8(std::string("\xc3")), fs::filesystem_error); -#else - CHECK(std::u16string(2,0xfffd) == fs::detail::fromUtf8(std::string("\xed\xa0\x80"))); - CHECK(std::u16string(1,0xfffd) == fs::detail::fromUtf8(std::string("\xc3"))); -#endif -} - -TEST_CASE("fs::detail::toUtf8", "[filesystem][fs.detail.utf8]") -{ - std::string t; - CHECK(std::string("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e") == fs::detail::toUtf8(std::u16string(u"\u00E4/\u20AC\U0001D11E"))); -#ifdef GHC_RAISE_UNICODE_ERRORS - CHECK_THROWS_AS(fs::detail::toUtf8(std::u16string(1, 0xd800)), fs::filesystem_error); - CHECK_THROWS_AS(fs::detail::appendUTF8(t, 0x200000), fs::filesystem_error); -#else - CHECK(std::string("\xEF\xBF\xBD") == fs::detail::toUtf8(std::u16string(1, 0xd800))); - fs::detail::appendUTF8(t, 0x200000); - CHECK(std::string("\xEF\xBF\xBD") == t); -#endif -} -#endif - -TEST_CASE("fs.path.generic - path::preferred_separator", "[filesystem][path][fs.path.generic]") -{ -#ifdef GHC_OS_WINDOWS - CHECK(fs::path::preferred_separator == '\\'); -#else - CHECK(fs::path::preferred_separator == '/'); -#endif -} - -#ifndef GHC_OS_WINDOWS -TEST_CASE("fs.path.generic - path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]") -{ - if (!has_host_root_name_support()) { - 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.)"); - } -} -#endif - -TEST_CASE("fs.path.construct - path constructors and destructor", "[filesystem][path][fs.path.construct]") -{ - CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string()); - std::string str = "/usr/local/bin"; -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - std::u8string u8str = u8"/usr/local/bin"; -#endif - std::u16string u16str = u"/usr/local/bin"; - std::u32string u32str = U"/usr/local/bin"; -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - CHECK(u8str == fs::path(u8str).generic_u8string()); -#endif - CHECK(u16str == fs::path(u16str).generic_u16string()); - CHECK(u32str == fs::path(u32str).generic_u32string()); - CHECK(str == fs::path(str, fs::path::format::generic_format)); - CHECK(str == fs::path(str.begin(), str.end())); - CHECK(fs::path(std::wstring(3, 67)) == "CCC"); -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - CHECK(str == fs::path(u8str.begin(), u8str.end())); -#endif - CHECK(str == fs::path(u16str.begin(), u16str.end())); - CHECK(str == fs::path(u32str.begin(), u32str.end())); -#ifdef GHC_FILESYSTEM_VERSION - CHECK(fs::path("///foo/bar") == "/foo/bar"); - CHECK(fs::path("//foo//bar") == "//foo/bar"); -#endif -#ifdef GHC_OS_WINDOWS - CHECK("\\usr\\local\\bin" == fs::path("/usr/local/bin")); - CHECK("C:\\usr\\local\\bin" == fs::path("C:\\usr\\local\\bin")); -#else - CHECK("/usr/local/bin" == fs::path("/usr/local/bin")); -#endif - if (has_host_root_name_support()) { - CHECK("//host/foo/bar" == fs::path("//host/foo/bar")); - } - -#if !defined(GHC_OS_WINDOWS) && !(defined(__GLIBCXX__) && !(defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 8))) && !defined(USE_STD_FS) - std::locale loc; - bool testUTF8Locale = false; - try { - if (const char* lang = std::getenv("LANG")) { - loc = std::locale(lang); - } - else { - loc = std::locale("en_US.UTF-8"); - } - std::string name = loc.name(); - if (name.length() > 5 && (name.substr(name.length() - 5) == "UTF-8" || name.substr(name.length() - 5) == "utf-8")) { - testUTF8Locale = true; - } - } - catch (std::runtime_error&) { - WARN("Couldn't create an UTF-8 locale!"); - } - if (testUTF8Locale) { - CHECK("/usr/local/bin" == fs::path("/usr/local/bin", loc)); - CHECK(str == fs::path(str.begin(), str.end(), loc)); - CHECK(str == fs::path(u16str.begin(), u16str.end(), loc)); - CHECK(str == fs::path(u32str.begin(), u32str.end(), loc)); - } -#endif -} - -TEST_CASE("fs.path.assign - path assignments", "[filesystem][path][fs.path.assign]") -{ - fs::path p1{"/foo/bar"}; - fs::path p2{"/usr/local"}; - fs::path p3; - p3 = p1; - REQUIRE(p1 == p3); - p3 = fs::path{"/usr/local"}; - REQUIRE(p2 == p3); - p3 = fs::path{L"/usr/local"}; - REQUIRE(p2 == p3); - p3.assign(L"/usr/local"); - REQUIRE(p2 == p3); -#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T) - p3 = fs::path::string_type{L"/foo/bar"}; - REQUIRE(p1 == p3); - p3.assign(fs::path::string_type{L"/usr/local"}); - REQUIRE(p2 == p3); -#else - p3 = fs::path::string_type{"/foo/bar"}; - REQUIRE(p1 == p3); - p3.assign(fs::path::string_type{"/usr/local"}); - REQUIRE(p2 == p3); -#endif - p3 = std::u16string(u"/foo/bar"); - REQUIRE(p1 == p3); - p3 = U"/usr/local"; - REQUIRE(p2 == p3); - p3.assign(std::u16string(u"/foo/bar")); - REQUIRE(p1 == p3); - std::string s{"/usr/local"}; - p3.assign(s.begin(), s.end()); - REQUIRE(p2 == p3); -} - -TEST_CASE("fs.path.append - path appends", "[filesystem][path][fs.path.append]") -{ -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("foo") / "c:/bar" == "c:/bar"); - CHECK(fs::path("foo") / "c:" == "c:"); - CHECK(fs::path("c:") / "" == "c:"); - CHECK(fs::path("c:foo") / "/bar" == "c:/bar"); - CHECK(fs::path("c:foo") / "c:bar" == "c:foo/bar"); -#else - CHECK(fs::path("foo") / "" == "foo/"); - CHECK(fs::path("foo") / "/bar" == "/bar"); - CHECK(fs::path("/foo") / "/" == "/"); - if (has_host_root_name_support()) { - CHECK(fs::path("//host/foo") / "/bar" == "/bar"); - CHECK(fs::path("//host") / "/" == "//host/"); - CHECK(fs::path("//host/foo") / "/" == "/"); - } -#endif - CHECK(fs::path("/foo/bar") / "some///other" == "/foo/bar/some/other"); - fs::path p1{"/tmp/test"}; - fs::path p2{"foobar.txt"}; - fs::path p3 = p1 / p2; - CHECK("/tmp/test/foobar.txt" == p3); - // TODO: append(first, last) -} - -TEST_CASE("fs.path.concat - path concatenation", "[filesystem][path][fs.path.concat]") -{ - CHECK((fs::path("foo") += fs::path("bar")) == "foobar"); - CHECK((fs::path("foo") += fs::path("/bar")) == "foo/bar"); - - CHECK((fs::path("foo") += std::string("bar")) == "foobar"); - CHECK((fs::path("foo") += std::string("/bar")) == "foo/bar"); - - CHECK((fs::path("foo") += "bar") == "foobar"); - CHECK((fs::path("foo") += "/bar") == "foo/bar"); - CHECK((fs::path("foo") += L"bar") == "foobar"); - CHECK((fs::path("foo") += L"/bar") == "foo/bar"); - - CHECK((fs::path("foo") += 'b') == "foob"); - CHECK((fs::path("foo") += '/') == "foo/"); - CHECK((fs::path("foo") += L'b') == "foob"); - CHECK((fs::path("foo") += L'/') == "foo/"); - - CHECK((fs::path("foo") += std::string("bar")) == "foobar"); - CHECK((fs::path("foo") += std::string("/bar")) == "foo/bar"); - - CHECK((fs::path("foo") += std::u16string(u"bar")) == "foobar"); - CHECK((fs::path("foo") += std::u16string(u"/bar")) == "foo/bar"); - - CHECK((fs::path("foo") += std::u32string(U"bar")) == "foobar"); - CHECK((fs::path("foo") += std::u32string(U"/bar")) == "foo/bar"); - - CHECK(fs::path("foo").concat("bar") == "foobar"); - CHECK(fs::path("foo").concat("/bar") == "foo/bar"); - CHECK(fs::path("foo").concat(L"bar") == "foobar"); - CHECK(fs::path("foo").concat(L"/bar") == "foo/bar"); - std::string bar = "bar"; - CHECK(fs::path("foo").concat(bar.begin(), bar.end()) == "foobar"); -#ifndef USE_STD_FS - CHECK((fs::path("/foo/bar") += "/some///other") == "/foo/bar/some/other"); -#endif - // TODO: contat(first, last) -} - -TEST_CASE("fs.path.modifiers - path modifiers", "[filesystem][path][fs.path.modifiers]") -{ - fs::path p = fs::path("/foo/bar"); - p.clear(); - CHECK(p == ""); - - // make_preferred() is a no-op -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("foo\\bar") == "foo/bar"); - CHECK(fs::path("foo\\bar").make_preferred() == "foo/bar"); -#else - CHECK(fs::path("foo\\bar") == "foo\\bar"); - CHECK(fs::path("foo\\bar").make_preferred() == "foo\\bar"); -#endif - CHECK(fs::path("foo/bar").make_preferred() == "foo/bar"); - - CHECK(fs::path("foo/bar").remove_filename() == "foo/"); - CHECK(fs::path("foo/").remove_filename() == "foo/"); - CHECK(fs::path("/foo").remove_filename() == "/"); - CHECK(fs::path("/").remove_filename() == "/"); - - CHECK(fs::path("/foo").replace_filename("bar") == "/bar"); - CHECK(fs::path("/").replace_filename("bar") == "/bar"); - CHECK(fs::path("/foo").replace_filename("b//ar") == "/b/ar"); - - CHECK(fs::path("/foo/bar.txt").replace_extension("odf") == "/foo/bar.odf"); - CHECK(fs::path("/foo/bar.txt").replace_extension() == "/foo/bar"); - CHECK(fs::path("/foo/bar").replace_extension("odf") == "/foo/bar.odf"); - CHECK(fs::path("/foo/bar").replace_extension(".odf") == "/foo/bar.odf"); - CHECK(fs::path("/foo/bar.").replace_extension(".odf") == "/foo/bar.odf"); - CHECK(fs::path("/foo/bar/").replace_extension("odf") == "/foo/bar/.odf"); - - fs::path p1 = "foo"; - fs::path p2 = "bar"; - p1.swap(p2); - CHECK(p1 == "bar"); - CHECK(p2 == "foo"); -} - -TEST_CASE("fs.path.native.obs - path native format observers", "[filesystem][path][fs.path.native.obs]") -{ -#ifdef GHC_OS_WINDOWS -#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T) - 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").wstring() == std::wstring(L"\u00E4\\\u20AC")); -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::u8string(u8"\u00E4\\\u20AC")); -#else - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::string("\xc3\xa4\\\xe2\x82\xac")); -#endif - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u16string() == std::u16string(u"\u00E4\\\u20AC")); - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4\\\U000020AC")); -#else - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").native() == fs::path::string_type("\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")); - 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"ä/€")); -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac")); -#else - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::string("\xc3\xa4/\xe2\x82\xac")); -#endif - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u16string() == std::u16string(u"\u00E4/\u20AC")); - INFO("This check might fail on GCC8 (with \"Illegal byte sequence\") due to not detecting the valid unicode codepoint U+1D11E."); - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e").u16string() == std::u16string(u"\u00E4/\u20AC\U0001D11E")); - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4/\U000020AC")); -#endif -} - -TEST_CASE("fs.path.generic.obs - 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")); -#endif - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_wstring() == std::wstring(L"\U000000E4/\U000020AC")); -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::u8string(u8"\u00E4/\u20AC")); -#else - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac")); -#endif - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC")); - CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC")); -#else - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string() == std::string("\xc3\xa4/\xe2\x82\xac")); -#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")); -#endif - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_wstring() == std::wstring(L"ä/€")); -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac")); -#else - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac")); -#endif - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC")); - CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC")); -#endif -} - -TEST_CASE("fs.path.compare - path compare", "[filesystem][path][fs.path.compare]") -{ - CHECK(fs::path("/foo/b").compare("/foo/a") > 0); - CHECK(fs::path("/foo/b").compare("/foo/b") == 0); - CHECK(fs::path("/foo/b").compare("/foo/c") < 0); - - CHECK(fs::path("/foo/b").compare(std::string("/foo/a")) > 0); - CHECK(fs::path("/foo/b").compare(std::string("/foo/b")) == 0); - CHECK(fs::path("/foo/b").compare(std::string("/foo/c")) < 0); - - CHECK(fs::path("/foo/b").compare(fs::path("/foo/a")) > 0); - CHECK(fs::path("/foo/b").compare(fs::path("/foo/b")) == 0); - CHECK(fs::path("/foo/b").compare(fs::path("/foo/c")) < 0); - -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("c:\\a\\b").compare("C:\\a\\b") == 0); - CHECK(fs::path("c:\\a\\b").compare("d:\\a\\b") != 0); - CHECK(fs::path("c:\\a\\b").compare("C:\\A\\b") != 0); -#endif - -#ifdef LWG_2936_BEHAVIOUR - CHECK(fs::path("/a/b/").compare("/a/b/c") < 0); - CHECK(fs::path("/a/b/").compare("a/c") > 0); -#endif // LWG_2936_BEHAVIOUR -} - -TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.decompose]") -{ - // root_name() - CHECK(fs::path("").root_name() == ""); - CHECK(fs::path(".").root_name() == ""); - CHECK(fs::path("..").root_name() == ""); - CHECK(fs::path("foo").root_name() == ""); - CHECK(fs::path("/").root_name() == ""); - CHECK(fs::path("/foo").root_name() == ""); - CHECK(fs::path("foo/").root_name() == ""); - CHECK(fs::path("/foo/").root_name() == ""); - CHECK(fs::path("foo/bar").root_name() == ""); - CHECK(fs::path("/foo/bar").root_name() == ""); - CHECK(fs::path("///foo/bar").root_name() == ""); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:/foo").root_name() == "C:"); - CHECK(fs::path("C:\\foo").root_name() == "C:"); - CHECK(fs::path("C:foo").root_name() == "C:"); -#endif - - // root_directory() - CHECK(fs::path("").root_directory() == ""); - CHECK(fs::path(".").root_directory() == ""); - CHECK(fs::path("..").root_directory() == ""); - CHECK(fs::path("foo").root_directory() == ""); - CHECK(fs::path("/").root_directory() == "/"); - CHECK(fs::path("/foo").root_directory() == "/"); - CHECK(fs::path("foo/").root_directory() == ""); - CHECK(fs::path("/foo/").root_directory() == "/"); - CHECK(fs::path("foo/bar").root_directory() == ""); - CHECK(fs::path("/foo/bar").root_directory() == "/"); - CHECK(fs::path("///foo/bar").root_directory() == "/"); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:/foo").root_directory() == "/"); - CHECK(fs::path("C:\\foo").root_directory() == "/"); - CHECK(fs::path("C:foo").root_directory() == ""); -#endif - - // root_path() - CHECK(fs::path("").root_path() == ""); - CHECK(fs::path(".").root_path() == ""); - CHECK(fs::path("..").root_path() == ""); - CHECK(fs::path("foo").root_path() == ""); - CHECK(fs::path("/").root_path() == "/"); - CHECK(fs::path("/foo").root_path() == "/"); - CHECK(fs::path("foo/").root_path() == ""); - CHECK(fs::path("/foo/").root_path() == "/"); - CHECK(fs::path("foo/bar").root_path() == ""); - CHECK(fs::path("/foo/bar").root_path() == "/"); - CHECK(fs::path("///foo/bar").root_path() == "/"); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:/foo").root_path() == "C:/"); - CHECK(fs::path("C:\\foo").root_path() == "C:/"); - CHECK(fs::path("C:foo").root_path() == "C:"); -#endif - - // relative_path() - CHECK(fs::path("").relative_path() == ""); - CHECK(fs::path(".").relative_path() == "."); - CHECK(fs::path("..").relative_path() == ".."); - CHECK(fs::path("foo").relative_path() == "foo"); - CHECK(fs::path("/").relative_path() == ""); - CHECK(fs::path("/foo").relative_path() == "foo"); - CHECK(fs::path("foo/").relative_path() == "foo/"); - CHECK(fs::path("/foo/").relative_path() == "foo/"); - CHECK(fs::path("foo/bar").relative_path() == "foo/bar"); - CHECK(fs::path("/foo/bar").relative_path() == "foo/bar"); - CHECK(fs::path("///foo/bar").relative_path() == "foo/bar"); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:/foo").relative_path() == "foo"); - CHECK(fs::path("C:\\foo").relative_path() == "foo"); - CHECK(fs::path("C:foo").relative_path() == "foo"); -#endif - - // parent_path() - CHECK(fs::path("").parent_path() == ""); - CHECK(fs::path(".").parent_path() == ""); - CHECK(fs::path("..").parent_path() == ""); // unintuitive but as defined in the standard - CHECK(fs::path("foo").parent_path() == ""); - CHECK(fs::path("/").parent_path() == "/"); - CHECK(fs::path("/foo").parent_path() == "/"); - CHECK(fs::path("foo/").parent_path() == "foo"); - CHECK(fs::path("/foo/").parent_path() == "/foo"); - CHECK(fs::path("foo/bar").parent_path() == "foo"); - CHECK(fs::path("/foo/bar").parent_path() == "/foo"); - CHECK(fs::path("///foo/bar").parent_path() == "/foo"); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:/foo").parent_path() == "C:/"); - CHECK(fs::path("C:\\foo").parent_path() == "C:/"); - CHECK(fs::path("C:foo").parent_path() == "C:"); -#endif - - // filename() - CHECK(fs::path("").filename() == ""); - CHECK(fs::path(".").filename() == "."); - CHECK(fs::path("..").filename() == ".."); - CHECK(fs::path("foo").filename() == "foo"); - CHECK(fs::path("/").filename() == ""); - CHECK(fs::path("/foo").filename() == "foo"); - CHECK(fs::path("foo/").filename() == ""); - CHECK(fs::path("/foo/").filename() == ""); - CHECK(fs::path("foo/bar").filename() == "bar"); - CHECK(fs::path("/foo/bar").filename() == "bar"); - CHECK(fs::path("///foo/bar").filename() == "bar"); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:/foo").filename() == "foo"); - CHECK(fs::path("C:\\foo").filename() == "foo"); - CHECK(fs::path("C:foo").filename() == "foo"); -#endif - - // stem() - CHECK(fs::path("/foo/bar.txt").stem() == "bar"); - { - fs::path p = "foo.bar.baz.tar"; - CHECK(p.extension() == ".tar"); - p = p.stem(); - CHECK(p.extension() == ".baz"); - p = p.stem(); - CHECK(p.extension() == ".bar"); - p = p.stem(); - CHECK(p == "foo"); - } - CHECK(fs::path("/foo/.profile").stem() == ".profile"); - CHECK(fs::path(".bar").stem() == ".bar"); - CHECK(fs::path("..bar").stem() == "."); - - // extension() - CHECK(fs::path("/foo/bar.txt").extension() == ".txt"); - CHECK(fs::path("/foo/bar").extension() == ""); - CHECK(fs::path("/foo/.profile").extension() == ""); - CHECK(fs::path(".bar").extension() == ""); - CHECK(fs::path("..bar").extension() == ".bar"); - - if (has_host_root_name_support()) { - // //host-based root-names - CHECK(fs::path("//host").root_name() == "//host"); - CHECK(fs::path("//host/foo").root_name() == "//host"); - CHECK(fs::path("//host").root_directory() == ""); - CHECK(fs::path("//host/foo").root_directory() == "/"); - CHECK(fs::path("//host").root_path() == "//host"); - CHECK(fs::path("//host/foo").root_path() == "//host/"); - CHECK(fs::path("//host").relative_path() == ""); - CHECK(fs::path("//host/foo").relative_path() == "foo"); - CHECK(fs::path("//host").parent_path() == "//host"); - CHECK(fs::path("//host/foo").parent_path() == "//host/"); - CHECK(fs::path("//host").filename() == ""); - CHECK(fs::path("//host/foo").filename() == "foo"); - } -} - -TEST_CASE("fs.path.query - path query", "[fielsystem][path][fs.path.query]") -{ - // empty - CHECK(fs::path("").empty()); - CHECK(!fs::path("foo").empty()); - - // has_root_path() - CHECK(!fs::path("foo").has_root_path()); - CHECK(!fs::path("foo/bar").has_root_path()); - CHECK(fs::path("/foo").has_root_path()); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:foo").has_root_path()); - CHECK(fs::path("C:/foo").has_root_path()); -#endif - - // has_root_name() - CHECK(!fs::path("foo").has_root_name()); - CHECK(!fs::path("foo/bar").has_root_name()); - CHECK(!fs::path("/foo").has_root_name()); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("C:foo").has_root_name()); - CHECK(fs::path("C:/foo").has_root_name()); -#endif - - // has_root_directory() - CHECK(!fs::path("foo").has_root_directory()); - CHECK(!fs::path("foo/bar").has_root_directory()); - CHECK(fs::path("/foo").has_root_directory()); -#ifdef GHC_OS_WINDOWS - CHECK(!fs::path("C:foo").has_root_directory()); - CHECK(fs::path("C:/foo").has_root_directory()); -#endif - - // has_relative_path() - CHECK(!fs::path("").has_relative_path()); - CHECK(!fs::path("/").has_relative_path()); - CHECK(fs::path("/foo").has_relative_path()); - - // has_parent_path() - CHECK(!fs::path("").has_parent_path()); - CHECK(!fs::path(".").has_parent_path()); - CHECK(!fs::path("..").has_parent_path()); // unintuitive but as defined in the standard - CHECK(!fs::path("foo").has_parent_path()); - CHECK(fs::path("/").has_parent_path()); - CHECK(fs::path("/foo").has_parent_path()); - CHECK(fs::path("foo/").has_parent_path()); - CHECK(fs::path("/foo/").has_parent_path()); - - // has_filename() - CHECK(fs::path("foo").has_filename()); - CHECK(fs::path("foo/bar").has_filename()); - CHECK(!fs::path("/foo/bar/").has_filename()); - - // has_stem() - CHECK(fs::path("foo").has_stem()); - CHECK(fs::path("foo.bar").has_stem()); - CHECK(fs::path(".profile").has_stem()); - CHECK(!fs::path("/foo/").has_stem()); - - // has_extension() - CHECK(!fs::path("foo").has_extension()); - CHECK(fs::path("foo.bar").has_extension()); - CHECK(!fs::path(".profile").has_extension()); - - // is_absolute() - CHECK(!fs::path("foo/bar").is_absolute()); -#ifdef GHC_OS_WINDOWS - CHECK(!fs::path("/foo").is_absolute()); - CHECK(!fs::path("c:foo").is_absolute()); - CHECK(fs::path("c:/foo").is_absolute()); -#else - CHECK(fs::path("/foo").is_absolute()); -#endif - - // is_relative() - CHECK(fs::path("foo/bar").is_relative()); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("/foo").is_relative()); - CHECK(fs::path("c:foo").is_relative()); - CHECK(!fs::path("c:/foo").is_relative()); -#else - CHECK(!fs::path("/foo").is_relative()); -#endif - - if (has_host_root_name_support()) { - CHECK(fs::path("//host").has_root_name()); - CHECK(fs::path("//host/foo").has_root_name()); - CHECK(fs::path("//host").has_root_path()); - CHECK(fs::path("//host/foo").has_root_path()); - CHECK(!fs::path("//host").has_root_directory()); - CHECK(fs::path("//host/foo").has_root_directory()); - CHECK(!fs::path("//host").has_relative_path()); - CHECK(fs::path("//host/foo").has_relative_path()); - CHECK(fs::path("//host/foo").is_absolute()); - CHECK(!fs::path("//host/foo").is_relative()); - } -} - -TEST_CASE("fs.path.gen - path generation", "[filesystem][path][fs.path.gen]") -{ - // lexically_normal() - CHECK(fs::path("foo/./bar/..").lexically_normal() == "foo/"); - CHECK(fs::path("foo/.///bar/../").lexically_normal() == "foo/"); - CHECK(fs::path("/foo/../..").lexically_normal() == "/"); - CHECK(fs::path("foo/..").lexically_normal() == "."); - CHECK(fs::path("ab/cd/ef/../../qw").lexically_normal() == "ab/qw"); - CHECK(fs::path("a/b/../../../c").lexically_normal() == "../c"); - CHECK(fs::path("../").lexically_normal() == ".."); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("\\/\\///\\/").lexically_normal() == "/"); - CHECK(fs::path("a/b/..\\//..///\\/../c\\\\/").lexically_normal() == "../c/"); - CHECK(fs::path("..a/b/..\\//..///\\/../c\\\\/").lexically_normal() == "../c/"); - CHECK(fs::path("..\\").lexically_normal() == ".."); -#endif - - // lexically_relative() - CHECK(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d"); - CHECK(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c"); - CHECK(fs::path("a/b/c").lexically_relative("a") == "b/c"); - CHECK(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../.."); - CHECK(fs::path("a/b/c").lexically_relative("a/b/c") == "."); - CHECK(fs::path("a/b").lexically_relative("c/d") == "../../a/b"); - CHECK(fs::path("a/b").lexically_relative("a/") == "b"); - if (has_host_root_name_support()) { - CHECK(fs::path("//host1/foo").lexically_relative("//host2.bar") == ""); - } -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("c:/foo").lexically_relative("/bar") == ""); - CHECK(fs::path("c:foo").lexically_relative("c:/bar") == ""); - CHECK(fs::path("foo").lexically_relative("/bar") == ""); - CHECK(fs::path("c:/foo/bar.txt").lexically_relative("c:/foo/") == "bar.txt"); - CHECK(fs::path("c:/foo/bar.txt").lexically_relative("C:/foo/") == "bar.txt"); -#else - CHECK(fs::path("/foo").lexically_relative("bar") == ""); - CHECK(fs::path("foo").lexically_relative("/bar") == ""); -#endif - - // lexically_proximate() - CHECK(fs::path("/a/d").lexically_proximate("/a/b/c") == "../../d"); - if (has_host_root_name_support()) { - CHECK(fs::path("//host1/a/d").lexically_proximate("//host2/a/b/c") == "//host1/a/d"); - } - CHECK(fs::path("a/d").lexically_proximate("/a/b/c") == "a/d"); -#ifdef GHC_OS_WINDOWS - CHECK(fs::path("c:/a/d").lexically_proximate("c:/a/b/c") == "../../d"); - CHECK(fs::path("c:/a/d").lexically_proximate("d:/a/b/c") == "c:/a/d"); - CHECK(fs::path("c:/foo").lexically_proximate("/bar") == "c:/foo"); - CHECK(fs::path("c:foo").lexically_proximate("c:/bar") == "c:foo"); - CHECK(fs::path("foo").lexically_proximate("/bar") == "foo"); -#else - CHECK(fs::path("/foo").lexically_proximate("bar") == "/foo"); - CHECK(fs::path("foo").lexically_proximate("/bar") == "foo"); -#endif -} - -static std::string iterateResult(const fs::path& path) -{ - std::ostringstream result; - for (fs::path::const_iterator i = path.begin(); i != path.end(); ++i) { - if (i != path.begin()) { - result << ","; - } - result << i->generic_string(); - } - return result.str(); -} - -static std::string reverseIterateResult(const fs::path& path) -{ - std::ostringstream result; - fs::path::const_iterator iter = path.end(); - bool first = true; - if (iter != path.begin()) { - do { - --iter; - if (!first) { - result << ","; - } - first = false; - result << iter->generic_string(); - } while (iter != path.begin()); - } - return result.str(); -} - -TEST_CASE("fs.path.itr - path iterators", "[filesystem][path][fs.path.itr]") -{ - CHECK(iterateResult(fs::path()).empty()); - CHECK("." == iterateResult(fs::path("."))); - CHECK(".." == iterateResult(fs::path(".."))); - CHECK("foo" == iterateResult(fs::path("foo"))); - CHECK("/" == iterateResult(fs::path("/"))); - CHECK("/,foo" == iterateResult(fs::path("/foo"))); - CHECK("foo," == iterateResult(fs::path("foo/"))); - CHECK("/,foo," == iterateResult(fs::path("/foo/"))); - CHECK("foo,bar" == iterateResult(fs::path("foo/bar"))); - CHECK("/,foo,bar" == iterateResult(fs::path("/foo/bar"))); -#ifndef USE_STD_FS - // ghc::filesystem enforces redundant slashes to be reduced to one - CHECK("/,foo,bar" == iterateResult(fs::path("///foo/bar"))); -#else - // typically std::filesystem keeps them - CHECK("///,foo,bar" == iterateResult(fs::path("///foo/bar"))); -#endif - CHECK("/,foo,bar," == iterateResult(fs::path("/foo/bar///"))); - CHECK("foo,.,bar,..," == iterateResult(fs::path("foo/.///bar/../"))); -#ifdef GHC_OS_WINDOWS - CHECK("C:,/,foo" == iterateResult(fs::path("C:/foo"))); -#endif - - CHECK(reverseIterateResult(fs::path()).empty()); - CHECK("." == reverseIterateResult(fs::path("."))); - CHECK(".." == reverseIterateResult(fs::path(".."))); - CHECK("foo" == reverseIterateResult(fs::path("foo"))); - CHECK("/" == reverseIterateResult(fs::path("/"))); - CHECK("foo,/" == reverseIterateResult(fs::path("/foo"))); - CHECK(",foo" == reverseIterateResult(fs::path("foo/"))); - CHECK(",foo,/" == reverseIterateResult(fs::path("/foo/"))); - CHECK("bar,foo" == reverseIterateResult(fs::path("foo/bar"))); - CHECK("bar,foo,/" == reverseIterateResult(fs::path("/foo/bar"))); -#ifndef USE_STD_FS - // ghc::filesystem enforces redundant slashes to be reduced to one - CHECK("bar,foo,/" == reverseIterateResult(fs::path("///foo/bar"))); -#else - // typically std::filesystem keeps them - CHECK("bar,foo,///" == reverseIterateResult(fs::path("///foo/bar"))); -#endif - CHECK(",bar,foo,/" == reverseIterateResult(fs::path("/foo/bar///"))); - CHECK(",..,bar,.,foo" == reverseIterateResult(fs::path("foo/.///bar/../"))); -#ifdef GHC_OS_WINDOWS - CHECK("foo,/,C:" == reverseIterateResult(fs::path("C:/foo"))); - CHECK("foo,C:" == reverseIterateResult(fs::path("C:foo"))); -#endif - { - fs::path p1 = "/foo/bar/test.txt"; - fs::path p2; - for (auto pe : p1) { - p2 /= pe; - } - CHECK(p1 == p2); - CHECK("bar" == *(--fs::path("/foo/bar").end())); - auto p = fs::path("/foo/bar"); - auto pi = p.end(); - pi--; - CHECK("bar" == *pi); - } - - if (has_host_root_name_support()) { - CHECK("foo" == *(--fs::path("//host/foo").end())); - auto p = fs::path("//host/foo"); - auto pi = p.end(); - pi--; - CHECK("foo" == *pi); - CHECK("//host" == iterateResult(fs::path("//host"))); - CHECK("//host,/,foo" == iterateResult(fs::path("//host/foo"))); - CHECK("//host" == reverseIterateResult(fs::path("//host"))); - CHECK("foo,/,//host" == reverseIterateResult(fs::path("//host/foo"))); - { - fs::path p1 = "//host/foo/bar/test.txt"; - fs::path p2; - for (auto pe : p1) { - p2 /= pe; - } - CHECK(p1 == p2); - } - } -} - -TEST_CASE("fs.path.nonmember - path non-member functions", "[filesystem][path][fs.path.nonmember]") -{ - fs::path p1("foo/bar"); - fs::path p2("some/other"); - fs::swap(p1, p2); - CHECK(p1 == "some/other"); - CHECK(p2 == "foo/bar"); - CHECK(hash_value(p1)); - CHECK(p2 < p1); - CHECK(p2 <= p1); - CHECK(p1 <= p1); - CHECK(!(p1 < p2)); - CHECK(!(p1 <= p2)); - CHECK(p1 > p2); - CHECK(p1 >= p2); - CHECK(p1 >= p1); - CHECK(!(p2 > p1)); - CHECK(!(p2 >= p1)); - CHECK(p1 != p2); - CHECK(p1 / p2 == "some/other/foo/bar"); -} - -TEST_CASE("fs.path.io - path inserter and extractor", "[filesystem][path][fs.path.io]") -{ - { - std::ostringstream os; - os << fs::path("/root/foo bar"); -#ifdef GHC_OS_WINDOWS - CHECK(os.str() == "\"\\\\root\\\\foo bar\""); -#else - CHECK(os.str() == "\"/root/foo bar\""); -#endif - } - { - std::ostringstream os; - os << fs::path("/root/foo\"bar"); -#ifdef GHC_OS_WINDOWS - CHECK(os.str() == "\"\\\\root\\\\foo\\\"bar\""); -#else - CHECK(os.str() == "\"/root/foo\\\"bar\""); -#endif - } - - { - std::istringstream is("\"/root/foo bar\""); - fs::path p; - is >> p; - CHECK(p == fs::path("/root/foo bar")); - CHECK((is.flags() & std::ios_base::skipws) == std::ios_base::skipws); - } - { - std::istringstream is("\"/root/foo bar\""); - is >> std::noskipws; - fs::path p; - is >> p; - CHECK(p == fs::path("/root/foo bar")); - CHECK((is.flags() & std::ios_base::skipws) != std::ios_base::skipws); - } - { - std::istringstream is("\"/root/foo\\\"bar\""); - fs::path p; - is >> p; - CHECK(p == fs::path("/root/foo\"bar")); - } - { - std::istringstream is("/root/foo"); - fs::path p; - is >> p; - CHECK(p == fs::path("/root/foo")); - } -} - -TEST_CASE("fs.path.factory - path factory functions", "[filesystem][path][fs.path.factory]") -{ - CHECK(fs::u8path("foo/bar") == fs::path("foo/bar")); - CHECK(fs::u8path("foo/bar") == fs::path("foo/bar")); - std::string str("/foo/bar/test.txt"); - CHECK(fs::u8path(str.begin(), str.end()) == str); -} - -TEST_CASE("fs.class.filesystem_error - class filesystem_error", "[filesystem][filesystem_error][fs.class.filesystem_error]") -{ - std::error_code ec(1, std::system_category()); - fs::filesystem_error fse("None", std::error_code()); - fse = fs::filesystem_error("Some error", ec); - CHECK(fse.code().value() == 1); - CHECK(!std::string(fse.what()).empty()); - CHECK(fse.path1().empty()); - CHECK(fse.path2().empty()); - fse = fs::filesystem_error("Some error", fs::path("foo/bar"), ec); - CHECK(!std::string(fse.what()).empty()); - CHECK(fse.path1() == "foo/bar"); - CHECK(fse.path2().empty()); - fse = fs::filesystem_error("Some error", fs::path("foo/bar"), fs::path("some/other"), ec); - CHECK(!std::string(fse.what()).empty()); - CHECK(fse.path1() == "foo/bar"); - CHECK(fse.path2() == "some/other"); -} - -constexpr fs::perms constExprOwnerAll() -{ - return fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec; -} - -TEST_CASE("fs.enum - enum class perms", "[filesystem][enum][fs.enum]") -{ - static_assert(constExprOwnerAll() == fs::perms::owner_all, "constexpr didn't result in owner_all"); - CHECK((fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec) == fs::perms::owner_all); - CHECK((fs::perms::group_read | fs::perms::group_write | fs::perms::group_exec) == fs::perms::group_all); - CHECK((fs::perms::others_read | fs::perms::others_write | fs::perms::others_exec) == fs::perms::others_all); - CHECK((fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all) == fs::perms::all); - CHECK((fs::perms::all | fs::perms::set_uid | fs::perms::set_gid | fs::perms::sticky_bit) == fs::perms::mask); -} - -TEST_CASE("fs.class.file_status - class file_status", "[filesystem][file_status][fs.class.file_status]") -{ - { - fs::file_status fs; - CHECK(fs.type() == fs::file_type::none); - CHECK(fs.permissions() == fs::perms::unknown); - } - { - fs::file_status fs{fs::file_type::regular}; - CHECK(fs.type() == fs::file_type::regular); - CHECK(fs.permissions() == fs::perms::unknown); - } - { - fs::file_status fs{fs::file_type::directory, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec}; - CHECK(fs.type() == fs::file_type::directory); - CHECK(fs.permissions() == fs::perms::owner_all); - fs.type(fs::file_type::block); - CHECK(fs.type() == fs::file_type::block); - fs.type(fs::file_type::character); - CHECK(fs.type() == fs::file_type::character); - fs.type(fs::file_type::fifo); - CHECK(fs.type() == fs::file_type::fifo); - fs.type(fs::file_type::symlink); - CHECK(fs.type() == fs::file_type::symlink); - fs.type(fs::file_type::socket); - CHECK(fs.type() == fs::file_type::socket); - fs.permissions(fs.permissions() | fs::perms::group_all | fs::perms::others_all); - CHECK(fs.permissions() == fs::perms::all); - } - { - fs::file_status fst(fs::file_type::regular); - fs::file_status fs(std::move(fst)); - CHECK(fs.type() == fs::file_type::regular); - CHECK(fs.permissions() == fs::perms::unknown); - } -#if !defined(USE_STD_FS) || defined(GHC_FILESYSTEM_RUNNING_CPP20) - { - fs::file_status fs1{fs::file_type::regular, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec}; - fs::file_status fs2{fs::file_type::regular, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec}; - fs::file_status fs3{fs::file_type::directory, fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec}; - fs::file_status fs4{fs::file_type::regular, fs::perms::owner_read | fs::perms::owner_write}; - CHECK(fs1 == fs2); - CHECK_FALSE(fs1 == fs3); - CHECK_FALSE(fs1 == fs4); - } -#endif -} - -TEST_CASE("fs.dir.entry - class directory_entry", "[filesystem][directory_entry][fs.dir.entry]") -{ - TemporaryDirectory t; - std::error_code ec; - auto de = fs::directory_entry(t.path()); - CHECK(de.path() == t.path()); - CHECK((fs::path)de == t.path()); - CHECK(de.exists()); - CHECK(!de.is_block_file()); - CHECK(!de.is_character_file()); - CHECK(de.is_directory()); - CHECK(!de.is_fifo()); - CHECK(!de.is_other()); - CHECK(!de.is_regular_file()); - CHECK(!de.is_socket()); - CHECK(!de.is_symlink()); - CHECK(de.status().type() == fs::file_type::directory); - ec.clear(); - CHECK(de.status(ec).type() == fs::file_type::directory); - CHECK(!ec); - CHECK_NOTHROW(de.refresh()); - fs::directory_entry none; - CHECK_THROWS_AS(none.refresh(), fs::filesystem_error); - ec.clear(); - CHECK_NOTHROW(none.refresh(ec)); - CHECK(ec); - CHECK_THROWS_AS(de.assign(""), fs::filesystem_error); - ec.clear(); - CHECK_NOTHROW(de.assign("", ec)); - CHECK(ec); - generateFile(t.path() / "foo", 1234); - auto now = fs::file_time_type::clock::now(); - CHECK_NOTHROW(de.assign(t.path() / "foo")); - CHECK_NOTHROW(de.assign(t.path() / "foo", ec)); - CHECK(!ec); - de = fs::directory_entry(t.path() / "foo"); - CHECK(de.path() == t.path() / "foo"); - CHECK(de.exists()); - CHECK(de.exists(ec)); - CHECK(!ec); - CHECK(!de.is_block_file()); - CHECK(!de.is_block_file(ec)); - CHECK(!ec); - CHECK(!de.is_character_file()); - CHECK(!de.is_character_file(ec)); - CHECK(!ec); - CHECK(!de.is_directory()); - CHECK(!de.is_directory(ec)); - CHECK(!ec); - CHECK(!de.is_fifo()); - CHECK(!de.is_fifo(ec)); - CHECK(!ec); - CHECK(!de.is_other()); - CHECK(!de.is_other(ec)); - CHECK(!ec); - CHECK(de.is_regular_file()); - CHECK(de.is_regular_file(ec)); - CHECK(!ec); - CHECK(!de.is_socket()); - CHECK(!de.is_socket(ec)); - CHECK(!ec); - CHECK(!de.is_symlink()); - CHECK(!de.is_symlink(ec)); - CHECK(!ec); - CHECK(de.file_size() == 1234); - CHECK(de.file_size(ec) == 1234); - CHECK(std::abs(std::chrono::duration_cast(de.last_write_time() - now).count()) < 3); - ec.clear(); - CHECK(std::abs(std::chrono::duration_cast(de.last_write_time(ec) - now).count()) < 3); - CHECK(!ec); -#ifndef GHC_OS_WEB - CHECK(de.hard_link_count() == 1); - CHECK(de.hard_link_count(ec) == 1); - CHECK(!ec); -#endif - CHECK_THROWS_AS(de.replace_filename("bar"), fs::filesystem_error); - CHECK_NOTHROW(de.replace_filename("foo")); - ec.clear(); - CHECK_NOTHROW(de.replace_filename("bar", ec)); - CHECK(ec); - auto de2none = fs::directory_entry(); - ec.clear(); -#ifndef GHC_OS_WEB - CHECK(de2none.hard_link_count(ec) == static_cast(-1)); - CHECK_THROWS_AS(de2none.hard_link_count(), fs::filesystem_error); - CHECK(ec); -#endif - ec.clear(); - CHECK_NOTHROW(de2none.last_write_time(ec)); - CHECK_THROWS_AS(de2none.last_write_time(), fs::filesystem_error); - CHECK(ec); - ec.clear(); - CHECK_THROWS_AS(de2none.file_size(), fs::filesystem_error); - CHECK(de2none.file_size(ec) == static_cast(-1)); - CHECK(ec); - ec.clear(); - CHECK(de2none.status().type() == fs::file_type::not_found); - CHECK(de2none.status(ec).type() == fs::file_type::not_found); - CHECK(ec); - generateFile(t.path() / "a"); - generateFile(t.path() / "b"); - auto d1 = fs::directory_entry(t.path() / "a"); - auto d2 = fs::directory_entry(t.path() / "b"); - CHECK(d1 < d2); - CHECK(!(d2 < d1)); - CHECK(d1 <= d2); - CHECK(!(d2 <= d1)); - CHECK(d2 > d1); - CHECK(!(d1 > d2)); - CHECK(d2 >= d1); - CHECK(!(d1 >= d2)); - CHECK(d1 != d2); - CHECK(!(d2 != d2)); - CHECK(d1 == d1); - CHECK(!(d1 == d2)); -} - -TEST_CASE("fs.class.directory_iterator - class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]") -{ - { - TemporaryDirectory t; - CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator()); - generateFile(t.path() / "test", 1234); - REQUIRE(fs::directory_iterator(t.path()) != fs::directory_iterator()); - auto iter = fs::directory_iterator(t.path()); - fs::directory_iterator iter2(iter); - fs::directory_iterator iter3, iter4; - iter3 = iter; - CHECK(iter->path().filename() == "test"); - CHECK(iter2->path().filename() == "test"); - CHECK(iter3->path().filename() == "test"); - iter4 = std::move(iter3); - CHECK(iter4->path().filename() == "test"); - CHECK(iter->path() == t.path() / "test"); - CHECK(!iter->is_symlink()); - CHECK(iter->is_regular_file()); - CHECK(!iter->is_directory()); - CHECK(iter->file_size() == 1234); - CHECK(++iter == fs::directory_iterator()); - CHECK_THROWS_AS(fs::directory_iterator(t.path() / "non-existing"), fs::filesystem_error); - int cnt = 0; - for(auto de : fs::directory_iterator(t.path())) { - ++cnt; - } - CHECK(cnt == 1); - } - if (is_symlink_creation_supported()) { - TemporaryDirectory t; - fs::path td = t.path() / "testdir"; - CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator()); - generateFile(t.path() / "test", 1234); - fs::create_directory(td); - REQUIRE_NOTHROW(fs::create_symlink(t.path() / "test", td / "testlink")); - std::error_code ec; - REQUIRE(fs::directory_iterator(td) != fs::directory_iterator()); - auto iter = fs::directory_iterator(td); - CHECK(iter->path().filename() == "testlink"); - CHECK(iter->path() == td / "testlink"); - CHECK(iter->is_symlink()); - CHECK(iter->is_regular_file()); - CHECK(!iter->is_directory()); - CHECK(iter->file_size() == 1234); - CHECK(++iter == fs::directory_iterator()); - } - { - // Issue #8: check if resources are freed when iterator reaches end() - TemporaryDirectory t(TempOpt::change_path); - auto p = fs::path("test/"); - fs::create_directory(p); - auto iter = fs::directory_iterator(p); - while (iter != fs::directory_iterator()) { - ++iter; - } - CHECK(fs::remove_all(p) == 1); - CHECK_NOTHROW(fs::create_directory(p)); - } -} - -TEST_CASE("fs.class.rec.dir.itr - class recursive_directory_iterator", "[filesystem][recursive_directory_iterator][fs.class.rec.dir.itr]") -{ - { - auto iter = fs::recursive_directory_iterator("."); - iter.pop(); - CHECK(iter == fs::recursive_directory_iterator()); - } - { - TemporaryDirectory t; - CHECK(fs::recursive_directory_iterator(t.path()) == fs::recursive_directory_iterator()); - generateFile(t.path() / "test", 1234); - REQUIRE(fs::recursive_directory_iterator(t.path()) != fs::recursive_directory_iterator()); - auto iter = fs::recursive_directory_iterator(t.path()); - CHECK(iter->path().filename() == "test"); - CHECK(iter->path() == t.path() / "test"); - CHECK(!iter->is_symlink()); - CHECK(iter->is_regular_file()); - CHECK(!iter->is_directory()); - CHECK(iter->file_size() == 1234); - CHECK(++iter == fs::recursive_directory_iterator()); - } - - { - TemporaryDirectory t; - fs::path td = t.path() / "testdir"; - fs::create_directories(td); - generateFile(td / "test", 1234); - REQUIRE(fs::recursive_directory_iterator(t.path()) != fs::recursive_directory_iterator()); - auto iter = fs::recursive_directory_iterator(t.path()); - - CHECK(iter->path().filename() == "testdir"); - CHECK(iter->path() == td); - CHECK(!iter->is_symlink()); - CHECK(!iter->is_regular_file()); - CHECK(iter->is_directory()); - - CHECK(++iter != fs::recursive_directory_iterator()); - - CHECK(iter->path().filename() == "test"); - CHECK(iter->path() == td / "test"); - CHECK(!iter->is_symlink()); - CHECK(iter->is_regular_file()); - CHECK(!iter->is_directory()); - CHECK(iter->file_size() == 1234); - - CHECK(++iter == fs::recursive_directory_iterator()); - } - { - TemporaryDirectory t; - std::error_code ec; - CHECK(fs::recursive_directory_iterator(t.path(), fs::directory_options::none) == fs::recursive_directory_iterator()); - CHECK(fs::recursive_directory_iterator(t.path(), fs::directory_options::none, ec) == fs::recursive_directory_iterator()); - CHECK(!ec); - CHECK(fs::recursive_directory_iterator(t.path(), ec) == fs::recursive_directory_iterator()); - CHECK(!ec); - generateFile(t.path() / "test"); - fs::recursive_directory_iterator rd1(t.path()); - CHECK(fs::recursive_directory_iterator(rd1) != fs::recursive_directory_iterator()); - fs::recursive_directory_iterator rd2(t.path()); - CHECK(fs::recursive_directory_iterator(std::move(rd2)) != fs::recursive_directory_iterator()); - fs::recursive_directory_iterator rd3(t.path(), fs::directory_options::skip_permission_denied); - CHECK(rd3.options() == fs::directory_options::skip_permission_denied); - fs::recursive_directory_iterator rd4; - rd4 = std::move(rd3); - CHECK(rd4 != fs::recursive_directory_iterator()); - CHECK_NOTHROW(++rd4); - CHECK(rd4 == fs::recursive_directory_iterator()); - fs::recursive_directory_iterator rd5; - rd5 = rd4; - } - { - TemporaryDirectory t(TempOpt::change_path); - generateFile("a"); - fs::create_directory("d1"); - fs::create_directory("d1/d2"); - generateFile("d1/b"); - generateFile("d1/c"); - generateFile("d1/d2/d"); - generateFile("e"); - auto iter = fs::recursive_directory_iterator("."); - std::multimap 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/b"); - generateFile("d1/c"); - generateFile("d1/d2/d"); - generateFile("e"); - std::multiset result; - for(auto de : fs::recursive_directory_iterator(".")) { - result.insert(de.path().generic_string()); - } - std::stringstream os; - for(auto p : result) { - os << p << ","; - } - CHECK(os.str() == "./a,./d1,./d1/b,./d1/c,./d1/d2,./d1/d2/d,./e,"); - } - { - 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 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 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 { - ++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],"); - } - if (is_symlink_creation_supported()) { - TemporaryDirectory t(TempOpt::change_path); - fs::create_directory("d1"); - generateFile("d1/a"); - fs::create_directory("d2"); - generateFile("d2/b"); - fs::create_directory_symlink("../d1", "d2/ds1"); - fs::create_directory_symlink("d3", "d2/ds2"); - std::multiset result; - REQUIRE_NOTHROW([&](){ - for (const auto& de : fs::recursive_directory_iterator("d2", fs::directory_options::follow_directory_symlink)) { - result.insert(de.path().generic_string()); - } - }()); - std::stringstream os; - for(const auto& p : result) { - os << p << ","; - } - CHECK(os.str() == "d2/b,d2/ds1,d2/ds1/a,d2/ds2,"); - os.str(""); - result.clear(); - REQUIRE_NOTHROW([&](){ - for (const auto& de : fs::recursive_directory_iterator("d2")) { - result.insert(de.path().generic_string()); - } - }()); - for(const auto& p : result) { - os << p << ","; - } - CHECK(os.str() == "d2/b,d2/ds1,d2/ds2,"); - } -} - -TEST_CASE("fs.op.absolute - absolute", "[filesystem][operations][fs.op.absolute]") -{ - CHECK(fs::absolute("") == fs::current_path() / ""); - CHECK(fs::absolute(fs::current_path()) == fs::current_path()); - CHECK(fs::absolute(".") == fs::current_path() / "."); - CHECK((fs::absolute("..") == fs::current_path().parent_path() || fs::absolute("..") == fs::current_path() / "..")); - CHECK(fs::absolute("foo") == fs::current_path() / "foo"); - std::error_code ec; - CHECK(fs::absolute("", ec) == fs::current_path() / ""); - CHECK(!ec); - CHECK(fs::absolute("foo", ec) == fs::current_path() / "foo"); - CHECK(!ec); -} - -TEST_CASE("fs.op.canonical - canonical", "[filesystem][operations][fs.op.canonical]") -{ - CHECK_THROWS_AS(fs::canonical(""), fs::filesystem_error); - { - std::error_code ec; - CHECK(fs::canonical("", ec) == ""); - CHECK(ec); - } - CHECK(fs::canonical(fs::current_path()) == fs::current_path()); - - CHECK(fs::canonical(".") == fs::current_path()); - CHECK(fs::canonical("..") == fs::current_path().parent_path()); - CHECK(fs::canonical("/") == fs::current_path().root_path()); - CHECK_THROWS_AS(fs::canonical("foo"), fs::filesystem_error); - { - std::error_code ec; - CHECK_NOTHROW(fs::canonical("foo", ec)); - CHECK(ec); - } - { - TemporaryDirectory t(TempOpt::change_path); - auto dir = t.path() / "d0"; - fs::create_directories(dir / "d1"); - generateFile(dir / "f0"); - fs::path rel(dir.filename()); - CHECK(fs::canonical(dir) == dir); - CHECK(fs::canonical(rel) == dir); - CHECK(fs::canonical(dir / "f0") == dir / "f0"); - CHECK(fs::canonical(rel / "f0") == dir / "f0"); - CHECK(fs::canonical(rel / "./f0") == dir / "f0"); - CHECK(fs::canonical(rel / "d1/../f0") == dir / "f0"); - } - - if (is_symlink_creation_supported()) { - TemporaryDirectory t(TempOpt::change_path); - fs::create_directory(t.path() / "dir1"); - generateFile(t.path() / "dir1/test1"); - fs::create_directory(t.path() / "dir2"); - fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym"); - CHECK(fs::canonical(t.path() / "dir2/dirSym/test1") == t.path() / "dir1/test1"); - } -} - -TEST_CASE("fs.op.copy - copy", "[filesystem][operations][fs.op.copy]") -{ - { - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - fs::create_directory("dir1"); - generateFile("dir1/file1"); - generateFile("dir1/file2"); - fs::create_directory("dir1/dir2"); - generateFile("dir1/dir2/file3"); - CHECK_NOTHROW(fs::copy("dir1", "dir3")); - CHECK(fs::exists("dir3/file1")); - CHECK(fs::exists("dir3/file2")); - CHECK(!fs::exists("dir3/dir2")); - CHECK_NOTHROW(fs::copy("dir1", "dir4", fs::copy_options::recursive, ec)); - CHECK(!ec); - CHECK(fs::exists("dir4/file1")); - CHECK(fs::exists("dir4/file2")); - CHECK(fs::exists("dir4/dir2/file3")); - fs::create_directory("dir5"); - generateFile("dir5/file1"); - CHECK_THROWS_AS(fs::copy("dir1/file1", "dir5/file1"), fs::filesystem_error); - CHECK_NOTHROW(fs::copy("dir1/file1", "dir5/file1", fs::copy_options::skip_existing)); - } - if (is_symlink_creation_supported()) { - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - fs::create_directory("dir1"); - generateFile("dir1/file1"); - 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")); - CHECK(fs::is_symlink("dir3/file1")); - CHECK(fs::exists("dir3/file2")); - CHECK(fs::is_symlink("dir3/file2")); - CHECK(fs::exists("dir3/dir2/file3")); - CHECK(fs::is_symlink("dir3/dir2/file3")); -#endif - } -#ifndef GHC_OS_WEB - { - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - fs::create_directory("dir1"); - generateFile("dir1/file1"); - generateFile("dir1/file2"); - fs::create_directory("dir1/dir2"); - generateFile("dir1/dir2/file3"); - auto f1hl = fs::hard_link_count("dir1/file1"); - auto f2hl = fs::hard_link_count("dir1/file2"); - auto f3hl = fs::hard_link_count("dir1/dir2/file3"); - CHECK_NOTHROW(fs::copy("dir1", "dir3", fs::copy_options::create_hard_links | fs::copy_options::recursive, ec)); - REQUIRE(!ec); - CHECK(fs::exists("dir3/file1")); - CHECK(fs::hard_link_count("dir1/file1") == f1hl + 1); - CHECK(fs::exists("dir3/file2")); - CHECK(fs::hard_link_count("dir1/file2") == f2hl + 1); - CHECK(fs::exists("dir3/dir2/file3")); - CHECK(fs::hard_link_count("dir1/dir2/file3") == f3hl + 1); - } -#endif -} - -TEST_CASE("fs.op.copy_file - copy_file", "[filesystem][operations][fs.op.copy_file]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo", 100); - CHECK(!fs::exists("bar")); - CHECK(fs::copy_file("foo", "bar")); - CHECK(fs::exists("bar")); - CHECK(fs::file_size("foo") == fs::file_size("bar")); - CHECK(fs::copy_file("foo", "bar2", ec)); - CHECK(!ec); - std::this_thread::sleep_for(std::chrono::seconds(1)); - generateFile("foo2", 200); - CHECK(fs::copy_file("foo2", "bar", fs::copy_options::update_existing)); - CHECK(fs::file_size("bar") == 200); - CHECK(!fs::copy_file("foo", "bar", fs::copy_options::update_existing)); - CHECK(fs::file_size("bar") == 200); - CHECK(fs::copy_file("foo", "bar", fs::copy_options::overwrite_existing)); - CHECK(fs::file_size("bar") == 100); - CHECK_THROWS_AS(fs::copy_file("foobar", "foobar2"), fs::filesystem_error); - CHECK_NOTHROW(fs::copy_file("foobar", "foobar2", ec)); - CHECK(ec); - CHECK(!fs::exists("foobar")); -} - -TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.copy_symlink]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo"); - fs::create_directory("dir"); - if (is_symlink_creation_supported()) { - fs::create_symlink("foo", "sfoo"); - fs::create_directory_symlink("dir", "sdir"); - CHECK_NOTHROW(fs::copy_symlink("sfoo", "sfooc")); - CHECK(fs::exists("sfooc")); - CHECK_NOTHROW(fs::copy_symlink("sfoo", "sfooc2", ec)); - CHECK(fs::exists("sfooc2")); - CHECK(!ec); - CHECK_NOTHROW(fs::copy_symlink("sdir", "sdirc")); - CHECK(fs::exists("sdirc")); - CHECK_NOTHROW(fs::copy_symlink("sdir", "sdirc2", ec)); - CHECK(fs::exists("sdirc2")); - CHECK(!ec); - } - CHECK_THROWS_AS(fs::copy_symlink("bar", "barc"), fs::filesystem_error); - CHECK_NOTHROW(fs::copy_symlink("bar", "barc", ec)); - CHECK(ec); -} - -TEST_CASE("fs.op.create_directories - create_directories", "[filesystem][operations][fs.op.create_directories]") -{ - TemporaryDirectory t; - fs::path p = t.path() / "testdir"; - fs::path p2 = p / "nested"; - REQUIRE(!fs::exists(p)); - REQUIRE(!fs::exists(p2)); - CHECK(fs::create_directories(p2)); - CHECK(fs::is_directory(p)); - CHECK(fs::is_directory(p2)); - CHECK(!fs::create_directories(p2)); -#ifdef TEST_LWG_2935_BEHAVIOUR - INFO("This test expects LWG #2935 result conformance."); - p = t.path() / "testfile"; - generateFile(p); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - bool created = false; - CHECK_NOTHROW((created = fs::create_directories(p))); - CHECK(!created); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - std::error_code ec; - CHECK_NOTHROW((created = fs::create_directories(p, ec))); - CHECK(!created); - CHECK(!ec); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - CHECK(!fs::create_directories(p, ec)); -#else - 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)); - CHECK(!fs::is_directory(p)); - CHECK_THROWS_AS(fs::create_directories(p), fs::filesystem_error); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - std::error_code ec; - CHECK_NOTHROW(fs::create_directories(p, ec)); - CHECK(ec); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - CHECK(!fs::create_directories(p, ec)); -#endif -} - -TEST_CASE("fs.op.create_directory - create_directory", "[filesystem][operations][fs.op.create_directory]") -{ - TemporaryDirectory t; - fs::path p = t.path() / "testdir"; - REQUIRE(!fs::exists(p)); - CHECK(fs::create_directory(p)); - CHECK(fs::is_directory(p)); - CHECK(!fs::is_regular_file(p)); - CHECK(fs::create_directory(p / "nested", p)); - CHECK(fs::is_directory(p / "nested")); - CHECK(!fs::is_regular_file(p / "nested")); -#ifdef TEST_LWG_2935_BEHAVIOUR - INFO("This test expects LWG #2935 result conformance."); - p = t.path() / "testfile"; - generateFile(p); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - bool created = false; - CHECK_NOTHROW((created = fs::create_directory(p))); - CHECK(!created); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - std::error_code ec; - CHECK_NOTHROW((created = fs::create_directory(p, ec))); - CHECK(!created); - CHECK(!ec); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - CHECK(!fs::create_directories(p, ec)); -#else - 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)); - CHECK(!fs::is_directory(p)); - REQUIRE_THROWS_AS(fs::create_directory(p), fs::filesystem_error); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - std::error_code ec; - REQUIRE_NOTHROW(fs::create_directory(p, ec)); - CHECK(ec); - CHECK(fs::is_regular_file(p)); - CHECK(!fs::is_directory(p)); - CHECK(!fs::create_directory(p, ec)); -#endif -} - -TEST_CASE("fs.op.create_directory_symlink - create_directory_symlink", "[filesystem][operations][fs.op.create_directory_symlink]") -{ - if (is_symlink_creation_supported()) { - TemporaryDirectory t; - fs::create_directory(t.path() / "dir1"); - generateFile(t.path() / "dir1/test1"); - fs::create_directory(t.path() / "dir2"); - fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym"); - CHECK(fs::exists(t.path() / "dir2/dirSym")); - CHECK(fs::is_symlink(t.path() / "dir2/dirSym")); - CHECK(fs::exists(t.path() / "dir2/dirSym/test1")); - CHECK(fs::is_regular_file(t.path() / "dir2/dirSym/test1")); - CHECK_THROWS_AS(fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym"), fs::filesystem_error); - std::error_code ec; - CHECK_NOTHROW(fs::create_directory_symlink(t.path() / "dir1", t.path() / "dir2/dirSym", ec)); - CHECK(ec); - } -} - -TEST_CASE("fs.op.create_hard_link - create_hard_link", "[filesystem][operations][fs.op.create_hard_link]") -{ -#ifndef GHC_OS_WEB - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo", 1234); - CHECK_NOTHROW(fs::create_hard_link("foo", "bar")); - CHECK(fs::exists("bar")); - CHECK(!fs::is_symlink("bar")); - CHECK_NOTHROW(fs::create_hard_link("foo", "bar2", ec)); - CHECK(fs::exists("bar2")); - CHECK(!fs::is_symlink("bar2")); - CHECK(!ec); - CHECK_THROWS_AS(fs::create_hard_link("nofoo", "bar"), fs::filesystem_error); - CHECK_NOTHROW(fs::create_hard_link("nofoo", "bar", ec)); - CHECK(ec); -#endif -} - -TEST_CASE("fs.op.create_symlink - create_symlink", "[filesystem][operations][fs.op.create_symlink]") -{ - if (is_symlink_creation_supported()) { - TemporaryDirectory t; - fs::create_directory(t.path() / "dir1"); - generateFile(t.path() / "dir1/test1"); - fs::create_directory(t.path() / "dir2"); - fs::create_symlink(t.path() / "dir1/test1", t.path() / "dir2/fileSym"); - CHECK(fs::exists(t.path() / "dir2/fileSym")); - CHECK(fs::is_symlink(t.path() / "dir2/fileSym")); - CHECK(fs::exists(t.path() / "dir2/fileSym")); - CHECK(fs::is_regular_file(t.path() / "dir2/fileSym")); - CHECK_THROWS_AS(fs::create_symlink(t.path() / "dir1", t.path() / "dir2/fileSym"), fs::filesystem_error); - std::error_code ec; - CHECK_NOTHROW(fs::create_symlink(t.path() / "dir1", t.path() / "dir2/fileSym", ec)); - CHECK(ec); - } -} - -TEST_CASE("fs.op.current_path - current_path", "[filesystem][operations][fs.op.current_path]") -{ - TemporaryDirectory t; - std::error_code ec; - fs::path p1 = fs::current_path(); - CHECK_NOTHROW(fs::current_path(t.path())); - CHECK(p1 != fs::current_path()); - CHECK_NOTHROW(fs::current_path(p1, ec)); - CHECK(!ec); - CHECK_THROWS_AS(fs::current_path(t.path() / "foo"), fs::filesystem_error); - CHECK(p1 == fs::current_path()); - CHECK_NOTHROW(fs::current_path(t.path() / "foo", ec)); - CHECK(ec); -} - -TEST_CASE("fs.op.equivalent - equivalent", "[filesystem][operations][fs.op.equivalent]") -{ - TemporaryDirectory t(TempOpt::change_path); - generateFile("foo", 1234); - CHECK(fs::equivalent(t.path() / "foo", "foo")); - if (is_symlink_creation_supported()) { - std::error_code ec(42, std::system_category()); - fs::create_symlink("foo", "foo2"); - CHECK(fs::equivalent("foo", "foo2")); - CHECK(fs::equivalent("foo", "foo2", ec)); - CHECK(!ec); - } -#ifdef TEST_LWG_2937_BEHAVIOUR - INFO("This test expects LWG #2937 result conformance."); - std::error_code ec; - bool result = false; - REQUIRE_THROWS_AS(fs::equivalent("foo", "foo3"), fs::filesystem_error); - CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec)); - CHECK(!result); - CHECK(ec); - ec.clear(); - CHECK_THROWS_AS(fs::equivalent("foo3", "foo"), fs::filesystem_error); - CHECK_NOTHROW(result = fs::equivalent("foo3", "foo", ec)); - CHECK(!result); - CHECK(ec); - ec.clear(); - CHECK_THROWS_AS(fs::equivalent("foo3", "foo4"), fs::filesystem_error); - CHECK_NOTHROW(result = fs::equivalent("foo3", "foo4", ec)); - CHECK(!result); - CHECK(ec); -#else - INFO("This test expects conformance predating LWG #2937 result."); - std::error_code ec; - bool result = false; - REQUIRE_NOTHROW(result = fs::equivalent("foo", "foo3")); - CHECK(!result); - CHECK_NOTHROW(result = fs::equivalent("foo", "foo3", ec)); - CHECK(!result); - CHECK(!ec); - ec.clear(); - CHECK_NOTHROW(result = fs::equivalent("foo3", "foo")); - CHECK(!result); - CHECK_NOTHROW(result = fs::equivalent("foo3", "foo", ec)); - CHECK(!result); - CHECK(!ec); - ec.clear(); - CHECK_THROWS_AS(result = fs::equivalent("foo4", "foo3"), fs::filesystem_error); - CHECK(!result); - CHECK_NOTHROW(result = fs::equivalent("foo4", "foo3", ec)); - CHECK(!result); - CHECK(ec); -#endif -} - -TEST_CASE("fs.op.exists - exists", "[filesystem][operations][fs.op.exists]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - CHECK(!fs::exists("")); - CHECK(!fs::exists("foo")); - CHECK(!fs::exists("foo", ec)); - CHECK(!ec); - ec = std::error_code(42, std::system_category()); - CHECK(!fs::exists("foo", ec)); -#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) - CHECK(!fs::exists(u8"foo")); -#endif - CHECK(!ec); - ec.clear(); - CHECK(fs::exists(t.path())); - CHECK(fs::exists(t.path(), ec)); - CHECK(!ec); - ec = std::error_code(42, std::system_category()); - CHECK(fs::exists(t.path(), ec)); - CHECK(!ec); -#if defined(GHC_OS_WINDOWS) && !defined(GHC_FILESYSTEM_FWD) - if (::GetFileAttributesW(L"C:\\fs-test") != INVALID_FILE_ATTRIBUTES) { - CHECK(fs::exists("C:\\fs-test")); - } -#endif -} - -TEST_CASE("fs.op.file_size - file_size", "[filesystem][operations][fs.op.file_size]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo", 0); - generateFile("bar", 1234); - CHECK(fs::file_size("foo") == 0); - ec = std::error_code(42, std::system_category()); - CHECK(fs::file_size("foo", ec) == 0); - CHECK(!ec); - ec.clear(); - CHECK(fs::file_size("bar") == 1234); - ec = std::error_code(42, std::system_category()); - CHECK(fs::file_size("bar", ec) == 1234); - CHECK(!ec); - ec.clear(); - CHECK_THROWS_AS(fs::file_size("foobar"), fs::filesystem_error); - CHECK(fs::file_size("foobar", ec) == static_cast(-1)); - CHECK(ec); - ec.clear(); -} - -#ifndef GHC_OS_WINDOWS -static uintmax_t getHardlinkCount(const fs::path& p) -{ - struct stat st = {}; - auto rc = ::lstat(p.c_str(), &st); - return rc == 0 ? st.st_nlink : ~0u; -} -#endif - -TEST_CASE("fs.op.hard_link_count - hard_link_count", "[filesystem][operations][fs.op.hard_link_count]") -{ -#ifndef GHC_OS_WEB - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; -#ifdef GHC_OS_WINDOWS - // windows doesn't implement "."/".." as hardlinks, so it - // starts with 1 and subdirectories don't change the count - CHECK(fs::hard_link_count(t.path()) == 1); - fs::create_directory("dir"); - CHECK(fs::hard_link_count(t.path()) == 1); -#else - // unix/bsd/linux typically implements "."/".." as hardlinks - // so an empty dir has 2 (from parent and the ".") and - // adding a subdirectory adds one due to its ".." - CHECK(fs::hard_link_count(t.path()) == getHardlinkCount(t.path())); - fs::create_directory("dir"); - CHECK(fs::hard_link_count(t.path()) == getHardlinkCount(t.path())); -#endif - generateFile("foo"); - CHECK(fs::hard_link_count(t.path() / "foo") == 1); - ec = std::error_code(42, std::system_category()); - CHECK(fs::hard_link_count(t.path() / "foo", ec) == 1); - CHECK(!ec); - CHECK_THROWS_AS(fs::hard_link_count(t.path() / "bar"), fs::filesystem_error); - CHECK_NOTHROW(fs::hard_link_count(t.path() / "bar", ec)); - CHECK(ec); - ec.clear(); -#else - WARN("Test for unsupportet features are disabled on JS/Wasm target."); -#endif -} - -class FileTypeMixFixture -{ -public: - FileTypeMixFixture() - : _t(TempOpt::change_path) - , _hasFifo(false) - , _hasSocket(false) - { - generateFile("regular"); - fs::create_directory("directory"); - if (is_symlink_creation_supported()) { - fs::create_symlink("regular", "file_symlink"); - fs::create_directory_symlink("directory", "dir_symlink"); - } -#if !defined(GHC_OS_WINDOWS) && !defined(GHC_OS_WEB) - REQUIRE(::mkfifo("fifo", 0644) == 0); - _hasFifo = true; - struct ::sockaddr_un addr; - addr.sun_family = AF_UNIX; - std::strncpy(addr.sun_path, "socket", sizeof(addr.sun_path)); - int fd = socket(PF_UNIX, SOCK_STREAM, 0); - bind(fd, (struct sockaddr*)&addr, sizeof addr); - _hasSocket = true; -#endif - } - - ~FileTypeMixFixture() {} - - bool has_fifo() const { return _hasFifo; } - - bool has_socket() const { return _hasSocket; } - - fs::path block_path() const - { - std::error_code ec; - if (fs::exists("/dev/sda", ec)) { - return "/dev/sda"; - } - else if (fs::exists("/dev/disk0", ec)) { - return "/dev/disk0"; - } - return fs::path(); - } - - fs::path character_path() const - { - std::error_code ec; - if (fs::exists("/dev/null", ec)) { - return "/dev/null"; - } - else if (fs::exists("NUL", ec)) { - return "NUL"; - } - return fs::path(); - } - fs::path temp_path() const { return _t.path(); } - -private: - TemporaryDirectory _t; - bool _hasFifo; - bool _hasSocket; -}; - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_block_file - is_block_file", "[filesystem][operations][fs.op.is_block_file]") -{ - std::error_code ec; - CHECK(!fs::is_block_file("directory")); - CHECK(!fs::is_block_file("regular")); - if (is_symlink_creation_supported()) { - CHECK(!fs::is_block_file("dir_symlink")); - CHECK(!fs::is_block_file("file_symlink")); - } - CHECK((has_fifo() ? !fs::is_block_file("fifo") : true)); - CHECK((has_socket() ? !fs::is_block_file("socket") : true)); - CHECK((block_path().empty() ? true : fs::is_block_file(block_path()))); - CHECK((character_path().empty() ? true : !fs::is_block_file(character_path()))); - CHECK_NOTHROW(fs::is_block_file("notfound")); - CHECK_NOTHROW(fs::is_block_file("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::not_found))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::regular))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::directory))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::symlink))); - CHECK(fs::is_block_file(fs::file_status(fs::file_type::block))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::character))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::fifo))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::socket))); - CHECK(!fs::is_block_file(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_character_file - is_character_file", "[filesystem][operations][fs.op.is_character_file]") -{ - std::error_code ec; - CHECK(!fs::is_character_file("directory")); - CHECK(!fs::is_character_file("regular")); - if (is_symlink_creation_supported()) { - CHECK(!fs::is_character_file("dir_symlink")); - CHECK(!fs::is_character_file("file_symlink")); - } - CHECK((has_fifo() ? !fs::is_character_file("fifo") : true)); - CHECK((has_socket() ? !fs::is_character_file("socket") : true)); - CHECK((block_path().empty() ? true : !fs::is_character_file(block_path()))); - CHECK((character_path().empty() ? true : fs::is_character_file(character_path()))); - CHECK_NOTHROW(fs::is_character_file("notfound")); - CHECK_NOTHROW(fs::is_character_file("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::not_found))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::regular))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::directory))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::symlink))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::block))); - CHECK(fs::is_character_file(fs::file_status(fs::file_type::character))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::fifo))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::socket))); - CHECK(!fs::is_character_file(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_directory - is_directory", "[filesystem][operations][fs.op.is_directory]") -{ - std::error_code ec; - CHECK(fs::is_directory("directory")); - CHECK(!fs::is_directory("regular")); - if (is_symlink_creation_supported()) { - CHECK(fs::is_directory("dir_symlink")); - CHECK(!fs::is_directory("file_symlink")); - } - CHECK((has_fifo() ? !fs::is_directory("fifo") : true)); - CHECK((has_socket() ? !fs::is_directory("socket") : true)); - CHECK((block_path().empty() ? true : !fs::is_directory(block_path()))); - CHECK((character_path().empty() ? true : !fs::is_directory(character_path()))); - CHECK_NOTHROW(fs::is_directory("notfound")); - CHECK_NOTHROW(fs::is_directory("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::not_found))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::regular))); - CHECK(fs::is_directory(fs::file_status(fs::file_type::directory))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::symlink))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::block))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::character))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::fifo))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::socket))); - CHECK(!fs::is_directory(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE("fs.op.is_empty - is_empty", "[filesystem][operations][fs.op.is_empty]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - CHECK(fs::is_empty(t.path())); - CHECK(fs::is_empty(t.path(), ec)); - CHECK(!ec); - generateFile("foo", 0); - generateFile("bar", 1234); - CHECK(fs::is_empty("foo")); - CHECK(fs::is_empty("foo", ec)); - CHECK(!ec); - CHECK(!fs::is_empty("bar")); - CHECK(!fs::is_empty("bar", ec)); - CHECK(!ec); - CHECK_THROWS_AS(fs::is_empty("foobar"), fs::filesystem_error); - bool result = false; - CHECK_NOTHROW(result = fs::is_empty("foobar", ec)); - CHECK(!result); - CHECK(ec); -} - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_fifo - is_fifo", "[filesystem][operations][fs.op.is_fifo]") -{ - std::error_code ec; - CHECK(!fs::is_fifo("directory")); - CHECK(!fs::is_fifo("regular")); - if (is_symlink_creation_supported()) { - CHECK(!fs::is_fifo("dir_symlink")); - CHECK(!fs::is_fifo("file_symlink")); - } - CHECK((has_fifo() ? fs::is_fifo("fifo") : true)); - CHECK((has_socket() ? !fs::is_fifo("socket") : true)); - CHECK((block_path().empty() ? true : !fs::is_fifo(block_path()))); - CHECK((character_path().empty() ? true : !fs::is_fifo(character_path()))); - CHECK_NOTHROW(fs::is_fifo("notfound")); - CHECK_NOTHROW(fs::is_fifo("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::not_found))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::regular))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::directory))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::symlink))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::block))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::character))); - CHECK(fs::is_fifo(fs::file_status(fs::file_type::fifo))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::socket))); - CHECK(!fs::is_fifo(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_other - is_other", "[filesystem][operations][fs.op.is_other]") -{ - std::error_code ec; - CHECK(!fs::is_other("directory")); - CHECK(!fs::is_other("regular")); - if (is_symlink_creation_supported()) { - CHECK(!fs::is_other("dir_symlink")); - CHECK(!fs::is_other("file_symlink")); - } - CHECK((has_fifo() ? fs::is_other("fifo") : true)); - CHECK((has_socket() ? fs::is_other("socket") : true)); - CHECK((block_path().empty() ? true : fs::is_other(block_path()))); - CHECK((character_path().empty() ? true : fs::is_other(character_path()))); - CHECK_NOTHROW(fs::is_other("notfound")); - CHECK_NOTHROW(fs::is_other("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_other(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_other(fs::file_status(fs::file_type::not_found))); - CHECK(!fs::is_other(fs::file_status(fs::file_type::regular))); - CHECK(!fs::is_other(fs::file_status(fs::file_type::directory))); - CHECK(!fs::is_other(fs::file_status(fs::file_type::symlink))); - CHECK(fs::is_other(fs::file_status(fs::file_type::block))); - CHECK(fs::is_other(fs::file_status(fs::file_type::character))); - CHECK(fs::is_other(fs::file_status(fs::file_type::fifo))); - CHECK(fs::is_other(fs::file_status(fs::file_type::socket))); - CHECK(fs::is_other(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_regular_file - is_regular_file", "[filesystem][operations][fs.op.is_regular_file]") -{ - std::error_code ec; - CHECK(!fs::is_regular_file("directory")); - CHECK(fs::is_regular_file("regular")); - if (is_symlink_creation_supported()) { - CHECK(!fs::is_regular_file("dir_symlink")); - CHECK(fs::is_regular_file("file_symlink")); - } - CHECK((has_fifo() ? !fs::is_regular_file("fifo") : true)); - CHECK((has_socket() ? !fs::is_regular_file("socket") : true)); - CHECK((block_path().empty() ? true : !fs::is_regular_file(block_path()))); - CHECK((character_path().empty() ? true : !fs::is_regular_file(character_path()))); - CHECK_NOTHROW(fs::is_regular_file("notfound")); - CHECK_NOTHROW(fs::is_regular_file("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::not_found))); - CHECK(fs::is_regular_file(fs::file_status(fs::file_type::regular))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::directory))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::symlink))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::block))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::character))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::fifo))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::socket))); - CHECK(!fs::is_regular_file(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_socket - is_socket", "[filesystem][operations][fs.op.is_socket]") -{ - std::error_code ec; - CHECK(!fs::is_socket("directory")); - CHECK(!fs::is_socket("regular")); - if (is_symlink_creation_supported()) { - CHECK(!fs::is_socket("dir_symlink")); - CHECK(!fs::is_socket("file_symlink")); - } - CHECK((has_fifo() ? !fs::is_socket("fifo") : true)); - CHECK((has_socket() ? fs::is_socket("socket") : true)); - CHECK((block_path().empty() ? true : !fs::is_socket(block_path()))); - CHECK((character_path().empty() ? true : !fs::is_socket(character_path()))); - CHECK_NOTHROW(fs::is_socket("notfound")); - CHECK_NOTHROW(fs::is_socket("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::not_found))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::regular))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::directory))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::symlink))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::block))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::character))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::fifo))); - CHECK(fs::is_socket(fs::file_status(fs::file_type::socket))); - CHECK(!fs::is_socket(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_symlink - is_symlink", "[filesystem][operations][fs.op.is_symlink]") -{ - std::error_code ec; - CHECK(!fs::is_symlink("directory")); - CHECK(!fs::is_symlink("regular")); - if (is_symlink_creation_supported()) { - CHECK(fs::is_symlink("dir_symlink")); - CHECK(fs::is_symlink("file_symlink")); - } - CHECK((has_fifo() ? !fs::is_symlink("fifo") : true)); - CHECK((has_socket() ? !fs::is_symlink("socket") : true)); - CHECK((block_path().empty() ? true : !fs::is_symlink(block_path()))); - CHECK((character_path().empty() ? true : !fs::is_symlink(character_path()))); - CHECK_NOTHROW(fs::is_symlink("notfound")); - CHECK_NOTHROW(fs::is_symlink("notfound", ec)); - CHECK(ec); - ec.clear(); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::none))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::not_found))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::regular))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::directory))); - CHECK(fs::is_symlink(fs::file_status(fs::file_type::symlink))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::block))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::character))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::fifo))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::socket))); - CHECK(!fs::is_symlink(fs::file_status(fs::file_type::unknown))); -} - -#ifndef GHC_OS_WEB -static fs::file_time_type timeFromString(const std::string& str) -{ - struct ::tm tm; - ::memset(&tm, 0, sizeof(::tm)); - std::istringstream is(str); - is >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S"); - if (is.fail()) { - throw std::exception(); - } - return from_time_t(std::mktime(&tm)); -} -#endif - -TEST_CASE("fs.op.last_write_time - last_write_time", "[filesystem][operations][fs.op.last_write_time]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - fs::file_time_type ft; - generateFile("foo"); - auto now = fs::file_time_type::clock::now(); - CHECK(std::abs(std::chrono::duration_cast(fs::last_write_time(t.path()) - now).count()) < 3); - CHECK(std::abs(std::chrono::duration_cast(fs::last_write_time("foo") - now).count()) < 3); - CHECK_THROWS_AS(fs::last_write_time("bar"), fs::filesystem_error); - CHECK_NOTHROW(ft = fs::last_write_time("bar", ec)); - CHECK(ft == fs::file_time_type::min()); - CHECK(ec); - ec.clear(); - if (is_symlink_creation_supported()) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - fs::create_symlink("foo", "foo2"); - ft = fs::last_write_time("foo"); - // checks that the time of the symlink is fetched - CHECK(ft == fs::last_write_time("foo2")); - } -#ifndef GHC_OS_WEB - auto nt = timeFromString("2015-10-21T04:30:00"); - CHECK_NOTHROW(fs::last_write_time(t.path() / "foo", nt)); - CHECK(std::abs(std::chrono::duration_cast(fs::last_write_time("foo") - nt).count()) < 1); - nt = timeFromString("2015-10-21T04:29:00"); - CHECK_NOTHROW(fs::last_write_time("foo", nt, ec)); - CHECK(std::abs(std::chrono::duration_cast(fs::last_write_time("foo") - nt).count()) < 1); - CHECK(!ec); - CHECK_THROWS_AS(fs::last_write_time("bar", nt), fs::filesystem_error); - CHECK_NOTHROW(fs::last_write_time("bar", nt, ec)); - CHECK(ec); -#endif -} - -TEST_CASE("fs.op.permissions - permissions", "[filesystem][operations][fs.op.permissions]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo", 512); - auto allWrite = fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write; - CHECK_NOTHROW(fs::permissions("foo", allWrite, fs::perm_options::remove)); - CHECK((fs::status("foo").permissions() & fs::perms::owner_write) != fs::perms::owner_write); -#if !defined(GHC_OS_WINDOWS) - if (geteuid() != 0) -#endif - { - CHECK_THROWS_AS(fs::resize_file("foo", 1024), fs::filesystem_error); - CHECK(fs::file_size("foo") == 512); - } - CHECK_NOTHROW(fs::permissions("foo", fs::perms::owner_write, fs::perm_options::add)); - CHECK((fs::status("foo").permissions() & fs::perms::owner_write) == fs::perms::owner_write); - CHECK_NOTHROW(fs::resize_file("foo", 2048)); - CHECK(fs::file_size("foo") == 2048); - CHECK_THROWS_AS(fs::permissions("bar", fs::perms::owner_write, fs::perm_options::add), fs::filesystem_error); - CHECK_NOTHROW(fs::permissions("bar", fs::perms::owner_write, fs::perm_options::add, ec)); - CHECK(ec); - CHECK_THROWS_AS(fs::permissions("bar", fs::perms::owner_write, static_cast(0)), fs::filesystem_error); -} - -TEST_CASE("fs.op.proximate - proximate", "[filesystem][operations][fs.op.proximate]") -{ - std::error_code ec; - CHECK(fs::proximate("/a/d", "/a/b/c") == "../../d"); - CHECK(fs::proximate("/a/d", "/a/b/c", ec) == "../../d"); - CHECK(!ec); - CHECK(fs::proximate("/a/b/c", "/a/d") == "../b/c"); - CHECK(fs::proximate("/a/b/c", "/a/d", ec) == "../b/c"); - CHECK(!ec); - CHECK(fs::proximate("a/b/c", "a") == "b/c"); - CHECK(fs::proximate("a/b/c", "a", ec) == "b/c"); - CHECK(!ec); - CHECK(fs::proximate("a/b/c", "a/b/c/x/y") == "../.."); - CHECK(fs::proximate("a/b/c", "a/b/c/x/y", ec) == "../.."); - CHECK(!ec); - CHECK(fs::proximate("a/b/c", "a/b/c") == "."); - CHECK(fs::proximate("a/b/c", "a/b/c", ec) == "."); - CHECK(!ec); - CHECK(fs::proximate("a/b", "c/d") == "../../a/b"); - CHECK(fs::proximate("a/b", "c/d", ec) == "../../a/b"); - CHECK(!ec); -#ifndef GHC_OS_WINDOWS - if (has_host_root_name_support()) { - CHECK(fs::proximate("//host1/a/d", "//host2/a/b/c") == "//host1/a/d"); - CHECK(fs::proximate("//host1/a/d", "//host2/a/b/c", ec) == "//host1/a/d"); - CHECK(!ec); - } -#endif -} - -TEST_CASE("fs.op.read_symlink - read_symlink", "[filesystem][operations][fs.op.read_symlink]") -{ - if (is_symlink_creation_supported()) { - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo"); - fs::create_symlink(t.path() / "foo", "bar"); - CHECK(fs::read_symlink("bar") == t.path() / "foo"); - CHECK(fs::read_symlink("bar", ec) == t.path() / "foo"); - CHECK(!ec); - CHECK_THROWS_AS(fs::read_symlink("foobar"), fs::filesystem_error); - CHECK(fs::read_symlink("foobar", ec) == fs::path()); - CHECK(ec); - } -} - -TEST_CASE("fs.op.relative - relative", "[filesystem][operations][fs.op.relative]") -{ - CHECK(fs::relative("/a/d", "/a/b/c") == "../../d"); - CHECK(fs::relative("/a/b/c", "/a/d") == "../b/c"); - CHECK(fs::relative("a/b/c", "a") == "b/c"); - CHECK(fs::relative("a/b/c", "a/b/c/x/y") == "../.."); - CHECK(fs::relative("a/b/c", "a/b/c") == "."); - CHECK(fs::relative("a/b", "c/d") == "../../a/b"); - std::error_code ec; - CHECK(fs::relative(fs::current_path() / "foo", ec) == "foo"); - CHECK(!ec); -} - -TEST_CASE("fs.op.remove - remove", "[filesystem][operations][fs.op.remove]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo"); - CHECK(fs::remove("foo")); - CHECK(!fs::exists("foo")); - CHECK(!fs::remove("foo")); - generateFile("foo"); - CHECK(fs::remove("foo", ec)); - CHECK(!fs::exists("foo")); - if (is_symlink_creation_supported()) { - generateFile("foo"); - fs::create_symlink("foo", "bar"); - CHECK(fs::exists(fs::symlink_status("bar"))); - CHECK(fs::remove("bar", ec)); - CHECK(fs::exists("foo")); - CHECK(!fs::exists(fs::symlink_status("bar"))); - } - CHECK(!fs::remove("bar")); - CHECK(!fs::remove("bar", ec)); - CHECK(!ec); -} - -TEST_CASE("fs.op.remove_all - remove_all", "[filesystem][operations][fs.op.remove_all]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo"); - CHECK(fs::remove_all("foo", ec) == 1); - CHECK(!ec); - ec.clear(); - CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator()); - fs::create_directories("dir1/dir1a"); - fs::create_directories("dir1/dir1b"); - generateFile("dir1/dir1a/f1"); - generateFile("dir1/dir1b/f2"); - CHECK_NOTHROW(fs::remove_all("dir1/non-existing", ec)); - CHECK(!ec); - CHECK(fs::remove_all("dir1/non-existing", ec) == 0); - CHECK(fs::remove_all("dir1") == 5); - CHECK(fs::directory_iterator(t.path()) == fs::directory_iterator()); -} - -TEST_CASE("fs.op.rename - rename", "[filesystem][operations][fs.op.rename]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo", 123); - fs::create_directory("dir1"); - CHECK_NOTHROW(fs::rename("foo", "bar")); - CHECK(!fs::exists("foo")); - CHECK(fs::exists("bar")); - CHECK_NOTHROW(fs::rename("dir1", "dir2")); - CHECK(fs::exists("dir2")); - generateFile("foo2", 42); - CHECK_NOTHROW(fs::rename("bar", "foo2")); - CHECK(fs::exists("foo2")); - CHECK(fs::file_size("foo2") == 123u); - CHECK(!fs::exists("bar")); - CHECK_NOTHROW(fs::rename("foo2", "foo", ec)); - CHECK(!ec); - CHECK_THROWS_AS(fs::rename("foobar", "barfoo"), fs::filesystem_error); - CHECK_NOTHROW(fs::rename("foobar", "barfoo", ec)); - CHECK(ec); - CHECK(!fs::exists("barfoo")); -} - -TEST_CASE("fs.op.resize_file - resize_file", "[filesystem][operations][fs.op.resize_file]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo", 1024); - CHECK(fs::file_size("foo") == 1024); - CHECK_NOTHROW(fs::resize_file("foo", 2048)); - CHECK(fs::file_size("foo") == 2048); - CHECK_NOTHROW(fs::resize_file("foo", 1000, ec)); - CHECK(!ec); - CHECK(fs::file_size("foo") == 1000); - CHECK_THROWS_AS(fs::resize_file("bar", 2048), fs::filesystem_error); - CHECK(!fs::exists("bar")); - CHECK_NOTHROW(fs::resize_file("bar", 4096, ec)); - CHECK(ec); - CHECK(!fs::exists("bar")); -} - -TEST_CASE("fs.op.space - space", "[filesystem][operations][fs.op.space]") -{ - { - fs::space_info si; - CHECK_NOTHROW(si = fs::space(fs::current_path())); - CHECK(si.capacity > 1024 * 1024); - CHECK(si.capacity > si.free); - CHECK(si.free >= si.available); - } - { - std::error_code ec; - fs::space_info si; - CHECK_NOTHROW(si = fs::space(fs::current_path(), ec)); - CHECK(si.capacity > 1024 * 1024); - CHECK(si.capacity > si.free); - CHECK(si.free >= si.available); - CHECK(!ec); - } -#ifndef GHC_OS_WEB // statvfs under emscripten always returns a result, so this tests would fail - { - std::error_code ec; - fs::space_info si; - CHECK_NOTHROW(si = fs::space("foobar42", ec)); - CHECK(si.capacity == static_cast(-1)); - CHECK(si.free == static_cast(-1)); - CHECK(si.available == static_cast(-1)); - CHECK(ec); - } - CHECK_THROWS_AS(fs::space("foobar42"), fs::filesystem_error); -#endif -} - -TEST_CASE("fs.op.status - status", "[filesystem][operations][fs.op.status]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - fs::file_status fs; - CHECK_NOTHROW(fs = fs::status("foo")); - CHECK(fs.type() == fs::file_type::not_found); - CHECK(fs.permissions() == fs::perms::unknown); - CHECK_NOTHROW(fs = fs::status("bar", ec)); - CHECK(fs.type() == fs::file_type::not_found); - CHECK(fs.permissions() == fs::perms::unknown); - CHECK(ec); - ec.clear(); - fs = fs::status(t.path()); - CHECK(fs.type() == fs::file_type::directory); - CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write)); - generateFile("foobar"); - fs = fs::status(t.path() / "foobar"); - CHECK(fs.type() == fs::file_type::regular); - CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write)); - if (is_symlink_creation_supported()) { - fs::create_symlink(t.path() / "foobar", t.path() / "barfoo"); - fs = fs::status(t.path() / "barfoo"); - CHECK(fs.type() == fs::file_type::regular); - CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write)); - } -} - -TEST_CASE("fs.op.status_known - status_known", "[filesystem][operations][fs.op.status_known]") -{ - CHECK(!fs::status_known(fs::file_status())); - CHECK(fs::status_known(fs::file_status(fs::file_type::not_found))); - CHECK(fs::status_known(fs::file_status(fs::file_type::regular))); - CHECK(fs::status_known(fs::file_status(fs::file_type::directory))); - CHECK(fs::status_known(fs::file_status(fs::file_type::symlink))); - CHECK(fs::status_known(fs::file_status(fs::file_type::character))); - CHECK(fs::status_known(fs::file_status(fs::file_type::fifo))); - CHECK(fs::status_known(fs::file_status(fs::file_type::socket))); - CHECK(fs::status_known(fs::file_status(fs::file_type::unknown))); -} - -TEST_CASE("fs.op.symlink_status - symlink_status", "[filesystem][operations][fs.op.symlink_status]") -{ - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - fs::file_status fs; - CHECK_NOTHROW(fs = fs::symlink_status("foo")); - CHECK(fs.type() == fs::file_type::not_found); - CHECK(fs.permissions() == fs::perms::unknown); - CHECK_NOTHROW(fs = fs::symlink_status("bar", ec)); - CHECK(fs.type() == fs::file_type::not_found); - CHECK(fs.permissions() == fs::perms::unknown); - CHECK(ec); - ec.clear(); - fs = fs::symlink_status(t.path()); - CHECK(fs.type() == fs::file_type::directory); - CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write)); - generateFile("foobar"); - fs = fs::symlink_status(t.path() / "foobar"); - CHECK(fs.type() == fs::file_type::regular); - CHECK((fs.permissions() & (fs::perms::owner_read | fs::perms::owner_write)) == (fs::perms::owner_read | fs::perms::owner_write)); - if (is_symlink_creation_supported()) { - fs::create_symlink(t.path() / "foobar", t.path() / "barfoo"); - fs = fs::symlink_status(t.path() / "barfoo"); - CHECK(fs.type() == fs::file_type::symlink); - } -} - -TEST_CASE("fs.op.temp_dir_path - temporary_directory_path", "[filesystem][operations][fs.op.temp_dir_path]") -{ - std::error_code ec; - CHECK_NOTHROW(fs::exists(fs::temp_directory_path())); - CHECK_NOTHROW(fs::exists(fs::temp_directory_path(ec))); - CHECK(!fs::temp_directory_path().empty()); - CHECK(!ec); -} - -TEST_CASE("fs.op.weakly_canonical - weakly_canonical", "[filesystem][operations][fs.op.weakly_canonical]") -{ - 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); - auto dir = t.path() / "d0"; - fs::create_directories(dir / "d1"); - generateFile(dir / "f0"); - fs::path rel(dir.filename()); - 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"); - CHECK(fs::weakly_canonical(rel / "d1/../f0") == dir / "f0"); - CHECK(fs::weakly_canonical(rel / "d1/../f1") == dir / "f1"); - CHECK(fs::weakly_canonical(rel / "d1/../f1/../f2") == dir / "f2"); - } -} - -TEST_CASE("std::string_view support", "[filesystem][fs.string_view]") -{ -#if defined(GHC_HAS_STD_STRING_VIEW) || defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) - -#if defined(GHC_HAS_STD_STRING_VIEW) - using namespace std::literals; - using string_view = std::string_view; - using wstring_view = std::wstring_view; -#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) - using string_view = std::experimental::string_view; - using wstring_view = std::experimental::wstring_view; -#endif - - { - std::string p("foo/bar"); - string_view sv(p); - CHECK(fs::path(sv, fs::path::format::generic_format).generic_string() == "foo/bar"); - fs::path p2("fo"); - p2 += string_view("o"); - CHECK(p2 == "foo"); - CHECK(p2.compare(string_view("foo")) == 0); - } - { - auto p = fs::path{"XYZ"}; - p /= string_view("Appendix"); - CHECK(p == "XYZ/Appendix"); - } - { - std::wstring p(L"foo/bar"); - wstring_view sv(p); - CHECK(fs::path(sv, fs::path::format::generic_format).generic_string() == "foo/bar"); - fs::path p2(L"fo"); - p2 += wstring_view(L"o"); - CHECK(p2 == "foo"); - CHECK(p2.compare(wstring_view(L"foo")) == 0); - } - -#else - WARN("std::string_view specific tests are empty without std::string_view."); -#endif -} - -TEST_CASE("Windows: Long filename support", "[filesystem][path][fs.path.win.long]") -{ -#ifdef GHC_OS_WINDOWS - TemporaryDirectory t(TempOpt::change_path); - char c = 'A'; - fs::path dir{"\\\\?\\"}; - dir += fs::current_path().u8string(); - for (; c <= 'Z'; ++c) { - std::string part = std::string(16, c); - dir /= part; - CHECK_NOTHROW(fs::create_directory(dir)); - CHECK(fs::exists(dir)); - generateFile(dir / "f0"); - REQUIRE(fs::exists(dir / "f0")); - } - CHECK(c > 'Z'); - fs::remove_all(fs::current_path() / std::string(16, 'A')); - CHECK(!fs::exists(fs::current_path() / std::string(16, 'A'))); - CHECK_NOTHROW(fs::create_directories(dir)); - CHECK(fs::exists(dir)); - generateFile(dir / "f0"); - CHECK(fs::exists(dir / "f0")); -#else - WARN("Windows specific tests are empty on non-Windows systems."); -#endif -} - -TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.namespaces]") -{ -#ifdef GHC_OS_WINDOWS - { - std::error_code ec; - fs::path p(R"(\\localhost\c$\Windows)"); - auto symstat = fs::symlink_status(p, ec); - CHECK(!ec); - auto p2 = fs::canonical(p, ec); - CHECK(!ec); - CHECK(p2 == p); - } - - struct TestInfo - { - std::string _path; - std::string _string; - std::string _rootName; - std::string _rootPath; - std::string _iterateResult; - }; - std::vector variants = { - {R"(C:\Windows\notepad.exe)", R"(C:\Windows\notepad.exe)", "C:", "C:\\", "C:,/,Windows,notepad.exe"}, -#ifdef USE_STD_FS - {R"(\\?\C:\Windows\notepad.exe)", R"(\\?\C:\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,C:,Windows,notepad.exe"}, - {R"(\??\C:\Windows\notepad.exe)", R"(\??\C:\Windows\notepad.exe)", "\\??", "\\??\\", "/??,/,C:,Windows,notepad.exe"}, -#else - {R"(\\?\C:\Windows\notepad.exe)", R"(\\?\C:\Windows\notepad.exe)", "C:", "C:\\", "//?/,C:,/,Windows,notepad.exe"}, - {R"(\??\C:\Windows\notepad.exe)", R"(\??\C:\Windows\notepad.exe)", "C:", "C:\\", "/?\?/,C:,/,Windows,notepad.exe"}, -#endif - {R"(\\.\C:\Windows\notepad.exe)", R"(\\.\C:\Windows\notepad.exe)", "\\\\.", "\\\\.\\", "//.,/,C:,Windows,notepad.exe"}, - {R"(\\?\HarddiskVolume1\Windows\notepad.exe)", R"(\\?\HarddiskVolume1\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,HarddiskVolume1,Windows,notepad.exe"}, - {R"(\\?\Harddisk0Partition1\Windows\notepad.exe)", R"(\\?\Harddisk0Partition1\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,Harddisk0Partition1,Windows,notepad.exe"}, - {R"(\\.\GLOBALROOT\Device\HarddiskVolume1\Windows\notepad.exe)", R"(\\.\GLOBALROOT\Device\HarddiskVolume1\Windows\notepad.exe)", "\\\\.", "\\\\.\\", "//.,/,GLOBALROOT,Device,HarddiskVolume1,Windows,notepad.exe"}, - {R"(\\?\GLOBALROOT\Device\Harddisk0\Partition1\Windows\notepad.exe)", R"(\\?\GLOBALROOT\Device\Harddisk0\Partition1\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,GLOBALROOT,Device,Harddisk0,Partition1,Windows,notepad.exe"}, - {R"(\\?\Volume{e8a4a89d-0000-0000-0000-100000000000}\Windows\notepad.exe)", R"(\\?\Volume{e8a4a89d-0000-0000-0000-100000000000}\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,Volume{e8a4a89d-0000-0000-0000-100000000000},Windows,notepad.exe"}, - {R"(\\LOCALHOST\C$\Windows\notepad.exe)", R"(\\LOCALHOST\C$\Windows\notepad.exe)", "\\\\LOCALHOST", "\\\\LOCALHOST\\", "//LOCALHOST,/,C$,Windows,notepad.exe"}, - {R"(\\?\UNC\C$\Windows\notepad.exe)", R"(\\?\UNC\C$\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,UNC,C$,Windows,notepad.exe"}, - {R"(\\?\GLOBALROOT\Device\Mup\C$\Windows\notepad.exe)", R"(\\?\GLOBALROOT\Device\Mup\C$\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,GLOBALROOT,Device,Mup,C$,Windows,notepad.exe"}, - }; - - for (auto ti : variants) { - INFO("Used path: " + ti._path); - auto p = fs::path(ti._path); - CHECK(p.string() == ti._string); - CHECK(p.is_absolute()); - CHECK(p.root_name().string() == ti._rootName); - CHECK(p.root_path().string() == ti._rootPath); - CHECK(iterateResult(p) == ti._iterateResult); - } -#else - WARN("Windows specific tests are empty on non-Windows systems."); -#endif -} - -TEST_CASE("Windows: Mapped folders handling ", "[filesystem][fs.win][fs.win.mapped]") -{ -#ifdef GHC_OS_WINDOWS - // this test expects a mapped volume on C:\\fs-test as is the case on the development test system - // does nothing on other systems - if (fs::exists("C:\\fs-test")) { - CHECK(fs::canonical("C:\\fs-test\\Test.txt").string() == "C:\\fs-test\\Test.txt"); - } -#else - WARN("Windows specific tests are empty on non-Windows systems."); -#endif -} - -TEST_CASE("Windows: Deletion of Read-only Files", "[filesystem][fs.win][fs.win.remove]") -{ -#ifdef GHC_OS_WINDOWS - TemporaryDirectory t(TempOpt::change_path); - std::error_code ec; - generateFile("foo", 512); - auto allWrite = fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write; - CHECK_NOTHROW(fs::permissions("foo", allWrite, fs::perm_options::remove)); - CHECK_NOTHROW(fs::remove("foo")); - CHECK(!fs::exists("foo")); -#else - WARN("Windows specific tests are empty on non-Windows systems."); -#endif -} diff --git a/vendor/FileSystem/test/fwd_test.cpp b/vendor/FileSystem/test/fwd_test.cpp deleted file mode 100644 index 7905707c..00000000 --- a/vendor/FileSystem/test/fwd_test.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// This test file is part of the fwd_test.cpp/impl_test.cpp pair -// and used to test the new optional two-part usage of ghc::filesystem -// where exactly one cpp includes fs_impl.hpp and all others use -// fs_fwd.hpp (to test this with maximum functionality, the unit tests -// are included here, signaling they should only include the fs_fwd.hpp) -#define GHC_FILESYSTEM_FWD_TEST -#include "filesystem_test.cpp" diff --git a/vendor/FileSystem/test/impl_test.cpp b/vendor/FileSystem/test/impl_test.cpp deleted file mode 100644 index 092be638..00000000 --- a/vendor/FileSystem/test/impl_test.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// This test file is part of the fwd_test.cpp/impl_test.cpp pair -// and used to test the new optional two-part usage of ghc::filesystem -// where exactly one cpp includes fs_impl.hpp and all others use -// fs_fwd.hpp (to test this with maximum functionality, the unit tests -// are included here, signaling they should only include the fs_fwd.hpp) -#include -#define CATCH_CONFIG_MAIN -#include "catch.hpp" diff --git a/vendor/FileSystem/test/multi1.cpp b/vendor/FileSystem/test/multi1.cpp deleted file mode 100644 index 6a9fac48..00000000 --- a/vendor/FileSystem/test/multi1.cpp +++ /dev/null @@ -1,42 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -#define CATCH_CONFIG_MAIN -#include "catch.hpp" - -#include -namespace fs = ghc::filesystem; - -// This test and the one in multi2.cpp doesn't actualy test relevant functionality, -// it is just used to check that it is possible to include filesystem.h in multiple -// source files. -TEST_CASE("Multifile-test 1", "[multi]") -{ - CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string()); - std::string str = "/usr/local/bin"; - std::u16string u16str = u"/usr/local/bin"; - std::u32string u32str = U"/usr/local/bin"; - CHECK(str == fs::path(str.begin(), str.end())); - CHECK(str == fs::path(u16str.begin(), u16str.end())); - CHECK(str == fs::path(u32str.begin(), u32str.end())); -} diff --git a/vendor/FileSystem/test/multi2.cpp b/vendor/FileSystem/test/multi2.cpp deleted file mode 100644 index 6bf32508..00000000 --- a/vendor/FileSystem/test/multi2.cpp +++ /dev/null @@ -1,40 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -#include "catch.hpp" -#include -namespace fs = ghc::filesystem; - -// This test and the one in multi1.cpp doesn't actualy test relevant functionality, -// it is just used to check that it is possible to include filesystem.h in multiple -// source files. -TEST_CASE("Multifile-test 2", "[multi]") -{ - CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string()); - std::string str = "/usr/local/bin"; - std::u16string u16str = u"/usr/local/bin"; - std::u32string u32str = U"/usr/local/bin"; - CHECK(str == fs::path(str.begin(), str.end())); - CHECK(str == fs::path(u16str.begin(), u16str.end())); - CHECK(str == fs::path(u32str.begin(), u32str.end())); -}