Compare commits

..

No commits in common. "master" and "v1.4.0" have entirely different histories.

20 changed files with 3043 additions and 8237 deletions

View File

@ -1,6 +1,6 @@
freebsd_task:
freebsd_instance:
image_family: freebsd-14-0
image_family: freebsd-12-1
install_script: |
pkg install -y cmake
pw groupadd testgrp
@ -11,24 +11,25 @@ freebsd_task:
test_script: |
sudo -u testuser .ci/unix-test.sh
rockylinux8_task:
centos7_task:
container:
image: docker.io/rockylinux:8
image: centos:7
install_script: |
dnf group install -y "Development Tools"
dnf install cmake -y
yum install -y centos-release-scl
yum install -y devtoolset-9
curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1
build_script: |
.ci/unix-build.sh
source /opt/rh/devtoolset-9/enable && PATH=$PATH:/usr/local/bin .ci/unix-build.sh
test_script: |
.ci/unix-test.sh
PATH=$PATH:/usr/local/bin .ci/unix-test.sh
rockylinux9_task:
centos8_task:
container:
image: docker.io/rockylinux:9
image: centos:8
install_script: |
dnf group install -y "Development Tools"
dnf install cmake -y
yum group install -y "Development Tools"
curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1
build_script: |
.ci/unix-build.sh
PATH=$PATH:/usr/local/bin .ci/unix-build.sh
test_script: |
.ci/unix-test.sh
PATH=$PATH:/usr/local/bin .ci/unix-test.sh

View File

@ -1,170 +0,0 @@
name: CMake Build Matrix
on: [ push, pull_request ]
jobs:
build:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- name: "Ubuntu 22.04 GCC 11"
os: ubuntu-22.04
build_type: Release
packages: ninja-build
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Ubuntu 22.04 Clang 13.0"
os: ubuntu-22.04
build_type: Release
packages: ninja-build libc++-13-dev libc++abi-13-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-13
cxx: clang++-13
- name: "Ubuntu 22.04 Clang 15.0"
os: ubuntu-22.04
build_type: Release
packages: ninja-build libc++-15-dev libc++abi-15-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-15
cxx: clang++-15
- name: "Ubuntu 22.04 GCC 11 coverage"
os: ubuntu-22.04
build_type: Debug
packages: ninja-build lcov
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Ubuntu 20.04 GCC 9.3"
os: ubuntu-20.04
build_type: Release
packages: ninja-build
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Ubuntu 20.04 Clang 10.0"
os: ubuntu-20.04
build_type: Release
packages: ninja-build
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-10
cxx: clang++-10
- name: "Ubuntu 20.04 Clang 11.0"
os: ubuntu-20.04
build_type: Release
packages: ninja-build clang-11 libc++-11-dev libc++abi-11-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-11
cxx: clang++-11
- name: "Ubuntu 20.04 GCC 9.3 coverage"
os: ubuntu-20.04
build_type: Debug
packages: ninja-build lcov
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Windows MSVC 2019"
os: windows-2019
build_type: Release
packages: ninja
generator: "Visual Studio 16 2019"
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: cl
cxx: cl
- name: "macOS 13 AppleClang"
os: macos-13
build_type: Release
packages: ninja
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang
cxx: clang++
steps:
- uses: actions/checkout@v2
- name: print environment
run: |
echo github.event.action: ${{ github.event.action }}
echo github.event_name: ${{ github.event_name }}
- name: Install dependencies on Ubuntu
if: startsWith(matrix.config.os, 'ubuntu')
shell: bash
run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt update
sudo apt install ${{ matrix.config.packages }}
- name: Install dependencies on windows
if: startsWith(matrix.config.os, 'windows')
run: |
choco install ${{ matrix.config.packages }}
- name: Install dependencies on macOS
if: startsWith(matrix.config.os, 'macos')
run: |
brew install ${{ matrix.config.packages }}
- name: Configure project
shell: bash
run: |
export CC=${{ matrix.config.cc }}
export CXX=${{ matrix.config.cxx }}
ninja --version
cmake --version
mkdir build
mkdir install
if [[ "${{ matrix.config.build_type }}" == "Debug" ]]; then
cmake -G "${{ matrix.config.generator }}" -S . -B build -DCMAKE_BUILD_TYPE=Debug -DGHC_COVERAGE=ON -DGHC_FILESYSTEM_TEST_COMPILE_FEATURES="${{ matrix.config.compatibility }}" -DCMAKE_INSTALL_PREFIX:PATH=install
else
cmake -G "${{ matrix.config.generator }}" -S . -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DGHC_FILESYSTEM_TEST_COMPILE_FEATURES="${{ matrix.config.compatibility }}" -DCMAKE_INSTALL_PREFIX:PATH=install
fi
- name: Build project
shell: bash
run: |
cmake --build build --config ${{ matrix.config.build_type }}
- name: Run tests
run: |
cd build && ctest -C ${{ matrix.config.build_type }}
- name: Collect coverage info
if: startsWith(matrix.config.build_type, 'Debug')
run: |
cd build
lcov --compat-libtool --directory . --capture --output-file coverage_output.info
lcov --remove coverage_output.info '/usr/*' '*/c++/*' '*.h' '*/catch.hpp' -o coverage.info
# sed -i 's|SF:/.*/filesystem/|SF:../|g' coverage.info
- name: Upload coverage info
if: startsWith(matrix.config.build_type, 'Debug')
env:
COVERALLS_DEBUG: true
NODE_COVERALLS_DEBUG: 1
uses: coverallsapp/github-action@master
with:
path-to-lcov: ${{ github.workspace }}/build/coverage.info
github-token: ${{ secrets.GITHUB_TOKEN }}

100
.travis.yml Normal file
View File

@ -0,0 +1,100 @@
language: cpp
dist: xenial # default distribution
os: linux # default os
sudo: false
matrix:
fast_finish: true
include:
- env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-5"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-6 && CXX=g++-6 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-6"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-7"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && GENERATOR='Unix Makefiles' && CONFIG=Debug && GHC_COVERAGE=1"
addons: { apt: { packages: ["g++-7", "lcov"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-8"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-9 && CXX=g++-9 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-9"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-5.0"] } }
- env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-6.0"] } }
- env: MATRIX_EVAL="CC=clang-7 && CXX=clang++-7 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-7", "libc++-7-dev", "libc++abi-7-dev"], sources: ["llvm-toolchain-xenial-7"] } }
- env: MATRIX_EVAL="CC=clang-8 && CXX=clang++-8 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-8", "libc++-8-dev", "libc++abi-8-dev"], sources: ["llvm-toolchain-xenial-8"] } }
- env: MATRIX_EVAL="CC=clang-9 && CXX=clang++-9 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-9", "libc++-9-dev", "libc++abi-9-dev"], sources: [{sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main', key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'}] } }
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode9.2
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode10.1
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode11.3
install:
- eval "${MATRIX_EVAL}"
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
gem install coveralls-lcov
fi
- $CC --version
- $CXX --version
- cmake --version
before_script:
- eval "${MATRIX_EVAL}"
- mkdir build
- cd build
- export VERBOSE=1
- |
if [ "${CONFIG}" = "Debug" ]; then
cmake -G"${GENERATOR}" -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} -DCMAKE_BUILD_TYPE=${CONFIG} -DGHC_COVERAGE=ON ..
else
cmake -G"${GENERATOR}" -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} -DCMAKE_BUILD_TYPE=${CONFIG} ..
fi
script:
- export VERBOSE=1
- cmake --build . --config ${CONFIG} --target filesystem_test
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
cmake --build . --config ${CONFIG} --target filesystem_test
test/filesystem_test
else
cmake --build . --config ${CONFIG}
ctest -C ${CONFIG} -E Windows
if [ -f "test/std_filesystem_test" ]; then
test/std_filesystem_test || true
fi
fi
after_success:
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
lcov --compat-libtool --directory . --capture --output-file coverage_output.info
lcov --remove coverage_output.info '/usr/*' '*/c++/*' '*.h' '*/catch.hpp' -o coverage.info
sed -i 's|SF:/.*/filesystem/|SF:../|g' coverage.info
coveralls-lcov coverage.info
fi

View File

@ -1,55 +1,41 @@
cmake_minimum_required(VERSION 3.7.2)
project(
ghcfilesystem,
VERSION 1.5.15
)
project(ghcfilesystem)
if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
if(POLICY CMP0110)
cmake_policy(SET CMP0110 NEW)
cmake_policy(PUSH)
cmake_policy(SET CMP0110 OLD)
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" OFF)
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()
include(CMakeDependentOption)
cmake_dependent_option(GHC_FILESYSTEM_BUILD_TESTING
"Enable tests" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
cmake_dependent_option(GHC_FILESYSTEM_BUILD_EXAMPLES
"Build examples" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
cmake_dependent_option(GHC_FILESYSTEM_WITH_INSTALL
"With install target" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
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()
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}")
endif()
add_library(ghc_filesystem INTERFACE)
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
target_include_directories(ghc_filesystem INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_options(ghc_filesystem INTERFACE "$<$<C_COMPILER_ID:MSVC>:/utf-8>")
target_compile_options(ghc_filesystem INTERFACE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
if(GHC_FILESYSTEM_BUILD_TESTING OR GHC_FILESYSTEM_BUILD_EXAMPLES)
get_directory_property(hasParent PARENT_DIRECTORY)
if(NOT hasParent)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(GhcHelper)
@ -67,24 +53,12 @@ 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)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config-version.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMinorVersion
)
install(
FILES
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem"
)
install(TARGETS ghc_filesystem EXPORT ghcFilesystemConfig)
install(EXPORT ghcFilesystemConfig NAMESPACE ghcFilesystem:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem)
endif()
if(POLICY CMP0110)
cmake_policy(POP)
endif()

704
README.md
View File

@ -1,58 +1,25 @@
![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://travis-ci.org/gulrak/filesystem.svg?branch=master)](https://travis-ci.org/gulrak/filesystem)
[![Build Status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem)
[![Build Status](https://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.14)
<!-- [![Build Status](https://cloud.drone.io/api/badges/gulrak/filesystem/status.svg?ref=refs/heads/master)](https://cloud.drone.io/gulrak/filesystem) -->
<!-- TOC -->
* [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 (ref)](#fspath--ref-)
* [Open Issues](#open-issues)
* [Windows](#windows)
* [Symbolic Links on Windows](#symbolic-links-on-windows)
* [Permissions](#permissions)
* [Release Notes](#release-notes)
<!-- TOC -->
[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.4.0)
# Filesystem
This is a header-only single-file `std::filesystem` compatible helper library,
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/11.6, Windows 10, Ubuntu 18.04, Ubuntu 20.04, CentOS 7, CentOS 8, FreeBSD 12,
Alpine ARM/ARM64 Linux and Solaris 10 but should work on other systems too, as long as you have
macOS 10.12/10.14/10.15, Windows 10, Ubuntu 18.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, QNX, and since 1.5.14
GNU/Hurd and Haiku is not backed up by automated testing but PRs and bug reports are welcome
for those too and they are reported to work.
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).
had reports of it being used on iOS (within sandboxing constraints).
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
*Test coverage is well above 90%, and starting with v1.3.6
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
@ -77,7 +44,7 @@ It is from after the standardization of C++17 but it contains the latest filesys
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).
and `std::u8string` handling from [Working Draft N4680](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!
@ -91,40 +58,36 @@ 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, FreeBSD and starting with v1.5.12 on Solaris.
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).
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
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._
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)
* 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
* Windows: Visual Studio 2017, Visual Studio 2015, Visual Studio 2019, MinGW GCC 6.3 (Win32), GCC 7.2 (Win64)
* 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~~ (The Drone build scripts stopped working,
as they where a contribution, I couldn't figure out what went wrong, any help appreciated.)
* Linux (Alpine ARM/ARM64): GCC 9.2.0
* FreeBSD: Clang 8.0
* Solaris: GCC 5.5
## 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
All tests agains 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.
@ -135,11 +98,9 @@ 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.
This generates `filesystem_test`, the binary that runs all tests.
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
@ -154,124 +115,86 @@ in the standard, and there might be issues in these implementations too.
### Downloads
The latest release version is [v1.5.14](https://github.com/gulrak/filesystem/tree/v1.5.14) and
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.5.14).
The latest pre-native-backend version is [v1.4.0](https://github.com/gulrak/filesystem/tree/v1.4.0) and
The latest release 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
The latest pre-C++20 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
or the `include/ghc` directory into your project folder oder 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
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#else
#include "filesystem.hpp"
namespace fs = ghc::filesystem;
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
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 allways 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
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "filesystem.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
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.**
**Be aware, as a header-only library, it is not hiding the fact, that it
uses system includes, so they "pollute" your global namespace.**
: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.
instead of `ghc/filesystem.hpp` when you want std::filesystem where
available and ghc::filesystem where not. It also enables the `wchar_t`
support on `ghc::filesystem` on Windows, so the resulting implementation
in the `fs` namespace will be compatible.
### Using it as Forwarding-/Implementation-Header
@ -279,9 +202,9 @@ available and `ghc::filesystem` where not.
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.
implementation details in a single cpp that includes `ghc/fs_impl.hpp` to
implement the needed code. That way system includes are only visible from
inside the cpp, 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
@ -292,46 +215,26 @@ If you use the forwarding/implementation approach, you can still use the dynamic
switching like this:
```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "fs_fwd.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/fs-fwd.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
```
@ -339,38 +242,22 @@ and in the implementation hiding cpp, you might use (before any include that inc
to take precedence:
```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!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
#include "fs_impl.hpp"
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#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.
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.
@ -382,7 +269,7 @@ as a git submodule, add the directory to your `CMakeLists.txt` with
to ensure correct include path that allow `#include <ghc/filesystem.hpp>`
to work.
The `CMakeLists.txt` offers a few options to customize its behavior:
The `CMakeLists.txt` offers a few options to customize its behaviour:
* `GHC_FILESYSTEM_BUILD_TESTING` - Compile tests, default is `OFF` when used as
a submodule, else `ON`.
@ -390,16 +277,6 @@ The `CMakeLists.txt` offers a few options to customize its behavior:
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).
### Bazel
Please use [hedronvision/bazel-cc-filesystem-backport](https://github.com/hedronvision/bazel-cc-filesystem-backport), which will automatically set everything up for you.
### Versioning
@ -407,7 +284,7 @@ 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
**Note:** Starting from v1.0.2 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.
@ -425,8 +302,8 @@ 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`.
**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
@ -438,13 +315,13 @@ 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`
They simply add an `open()` method and a constuctor 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
fetches the command line arguments als Unicode strings from the OS with
```cpp
::CommandLineToArgvW(::GetCommandLineW(), &argc)
@ -466,7 +343,7 @@ int main(int argc, char* argv[])
exit(EXIT_FAILURE);
}
// now use argc/argv as usual, they have utf-8 encoding on windows
// now use argc/argv as usual, they have utf-8 enconding on windows
// ...
return 0;
@ -484,8 +361,8 @@ 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.
classes, it derived some constraints of it, leading to some differences
between this and the standard C++17/C++20 API.
### LWG Defects
@ -504,7 +381,7 @@ where a regular file of the same name prohibits the creation of a directory and
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
[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revison
P1161R1 was agreed upon on Kona 2019 meeting [see merge](https://github.com/cplusplus/draft/issues/2703)
and GCC by now switched to following its proposal
([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)).
@ -521,24 +398,8 @@ 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.
ghc::filesystem under C++17.
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
@ -546,27 +407,49 @@ 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
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`.
```cpp
filesystem::path::string_type
filesystem::path::value_type
```
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
In Windows, an implementation should use `std::wstring` and `wchar_t` as types used
for the native representation, but as I'm a big fan of the
["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/), I decided
agains it for now. If you need to call some Windows API, use the W-variant
with 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`._
Unicode variant independant of the `UNICODE` macro and makes sharing code
between Windows, Linux and macOS easier.
Starting with v1.2.0 `ghc::filesystem` has the option to select the more
standard conforming APi with `wchar_t` and `std::wstring` on Windows by
defining `GHC_WIN_WSTRING_STRING_TYPE`. This define has no effect on other
platforms and will be set by the helping headers `ghc/fs_std.hpp` and
the pair `ghc/fs_std_fwd.hpp`/`ghc/fs_std_impl.hpp` to enhance compatibility.
```cpp
const path::string_type& path::native() const /*noexcept*/;
const path::value_type *path::c_str() const /*noexcept*/;
```
These two can not be `noexcept` with the current implementation. This due
to the fact, that internally path is working on the generic path version
only, and the getters need to do a conversion to native path format.
```cpp
const path::string_type& path::generic_string() const;
```
This returns a const reference, instead of a value, because it can. This
implementation uses the generic representation for internal workings, so
it's "free" to return that.
```cpp
std::string path::u8string() const;
@ -593,22 +476,20 @@ 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.
As the complete inner mechanics of this implementation `fs::path` are working
on the generic format, it is the internal representation. So creating any mixed
slash `fs::path` object under Windows (e.g. with `"C:\foo/bar"`) will lead to a
unified path with `"C:\foo\bar"` via `native()` and `"C:/foo/bar"` via
`generic_string()` API.
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
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`
has the exception where `*this == *this.root_name()` and `p == preferred_seperator`
a normal append will be done, to allow:
```cpp
@ -618,12 +499,37 @@ for (auto p : p1) p2 /= p;
ASSERT(p1 == p2);
```
For all non-host-leading paths the behavior will match the one described by
For all non-host-leading paths the behaviour will match the one described by
the standard.
#### fs.op.copy ([ref](https://en.cppreference.com/w/cpp/filesystem/copy))
Then there is `fs::copy`. The tests in the suite fail partially with C++17 `std::filesystem`
on GCC/Clang. They complain about a copy call with `fs::copy_options::recursive` combined
with `fs::copy_options::create_symlinks` or `fs::copy_options::create_hard_links` if the
source is a directory. There is nothing in the standard that forbids this combination
and it is the only way to deep-copy a tree while only create links for the files.
There is [LWG #2682](https://wg21.cmeerw.net/lwg/issue2682) that supports this
interpretation, but the issue ignores the usefulness of the combination with recursive
and part of the justification for the proposed solution is "we did it so for almost two years".
But this makes `fs::copy` with `fs::copy_options::create_symlinks` or `fs::copy_options::create_hard_links`
just a more complicated syntax for the `fs::create_symlink` or `fs::create_hardlink` operation
and I don't want to believe, that this was the intention of the original writing.
As there is another issue related to copy, with a different take on the description.
**Note:** With v1.1.2 I decided to integrate a behavior switch for this and make the LWG #2682
the default.
## Open Issues
### General Known Issues
There are still some methods that break the `noexcept` clause, some
are related to LWG defects, some are due to my implementation. I
work on fixing the later ones, and might in cases where there is no
way of implementing the feature without risk of an exception, break
conformance and remove the `noexcept`.
### Windows
#### Symbolic Links on Windows
@ -631,7 +537,7 @@ the standard.
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.
(2018) rarely used, still they are supported with this implementation.
#### Permissions
@ -646,206 +552,6 @@ to the expected behavior.
## Release Notes
### v1.5.15 (wip)
* Fix for [#166](https://github.com/gulrak/filesystem/issues/166),
`extension()` did return non empty result for the directory name
`".."`
### [v1.5.14](https://github.com/gulrak/filesystem/releases/tag/v1.5.14)
* Pull request [#163](https://github.com/gulrak/filesystem/pull/163), build
support for Haiku (also fixes [#159](https://github.com/gulrak/filesystem/issues/159))
* Pull request [#162](https://github.com/gulrak/filesystem/pull/162), fix for
directory iterator treating all files subsequent to a symlink as symlink
on Windows
* Pull request [#161](https://github.com/gulrak/filesystem/pull/161), the
CMake alias `ghcFilesystem::ghc_filesystem` is now set unconditionally
* Fix for [#160](https://github.com/gulrak/filesystem/issues/160), the cmake
config now only sets install targets by default if the project is no
subproject, as documented
* Fix for [#157](https://github.com/gulrak/filesystem/issues/157), suppress
C4191 warning on MSVC for GetProcAddress casts
* Fix for [#156](https://github.com/gulrak/filesystem/issues/156), on POSIX
`stem()`, `filename()` and `extension()` of `fs::path` would return wrong
result if a colon was in the filename
* Pull request [#154](https://github.com/gulrak/filesystem/pull/145), build
support for GNU/Hurd
* Pull request [#153](https://github.com/gulrak/filesystem/pull/153), fixed
`fs::last_write_time(path, time, ec)` setter on iOS, tvOS and watchOS
* Fix for [#151](https://github.com/gulrak/filesystem/issues/156),
`fs::directory_entry::refresh()` now, consistently with `status()` will not
throw on symlinks to non-existing targets, but make the entry have
`file_type::not_found` as the type
* Pull request [#149](https://github.com/gulrak/filesystem/pull/149), add
version to CMake project and export it
* Fix for [#146](https://github.com/gulrak/filesystem/issues/146), handle `EINTR`
on POSIX directory iteration and file copy to avoid errors on network
filesystems
* Pull request [#145](https://github.com/gulrak/filesystem/pull/145), fix for
Y2038 bug in timeToFILETIME on Windows
* Pull request [#144](https://github.com/gulrak/filesystem/pull/144), `fs::copy_file()`
now also copies the permissions
* Pull request [#143](https://github.com/gulrak/filesystem/pull/143), fix
for `fs::copy_file()` ignoring the `skip_existing` option.
### [v1.5.12](https://github.com/gulrak/filesystem/releases/tag/v1.5.12)
* Fix for [#142](https://github.com/gulrak/filesystem/issues/142), removed need
for `GHC_NO_DIRENT_D_TYPE` on systems that don't support `dirent::d_type` and
fixed build configuration and tests to support Solaris as new platform.
* Pull request [#138](https://github.com/gulrak/filesystem/pull/138), if the
platform uses the POSIX backend and has no `PATH_MAX`, one is defined.
* Pull request [#137](https://github.com/gulrak/filesystem/pull/137), update
of Catch2 to version v2.13.7
* Added macOS 11 to the automatically tested platforms.
### [v1.5.10](https://github.com/gulrak/filesystem/releases/tag/v1.5.10)
* Pull request [#136](https://github.com/gulrak/filesystem/pull/136), the Windows
implementation used some unnecessary expensive shared pointer for resource
management and these where replaced by a dedicated code.
* Fix for [#132](https://github.com/gulrak/filesystem/issues/132), pull request
[#135](https://github.com/gulrak/filesystem/pull/135), `fs::remove_all` now
just deletes symbolic links instead of following them.
* Pull request [#133](https://github.com/gulrak/filesystem/pull/133), fix for
`fs::space` where a numerical overflow could happen in a multiplication.
* 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 `<Availability.h>`
was included before `<ghc/fs_std.hpp>` or `<ghc/fs_std_fwd.hpp>`/`<ghc/fs_std_impl.hpp>`.
* 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 `<string_view>` or `<experimental/string_view>`
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.<br>
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:
@ -895,8 +601,8 @@ to the expected behavior.
`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
insensitive on Windows. This fix also adds the new behaviour switch `LWG_2936_BEHAVIOUR`
that allows to enable post C++17 `fs::path::compare` behaviour, 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.
@ -937,7 +643,7 @@ to the expected behavior.
* 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.
part of the CI infrastucture with the service of Cirrus CI.
* Pull request [#50](https://github.com/gulrak/filesystem/pull/50), adaptive cast to
`timespec` fields to avoid warnings.
@ -955,10 +661,10 @@ to the expected behavior.
* 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,
on Windows didn't replace an axisting 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
forwarding use via `fs_fwd.hpp` or `fs_std_fwd.hpp` der 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.
@ -990,20 +696,20 @@ to the expected behavior.
* 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.
* Bugfix for [#36](https://github.com/gulrak/filesystem/issues/36), warings
on Xcode 11.2 due to unhelpfull 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
examples can now be disabled in CMake via seting `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
`fs::path::preferred_seperator` 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.
@ -1042,7 +748,7 @@ to the expected behavior.
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
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
@ -1053,9 +759,9 @@ to the expected behavior.
* 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
as `readdir_r` is now depricated, I decided to drop it and the resulting
code is much easier, shorter and due to more refactoring faster
* Fix for crashing unit tests against MSVC C++17 `std::filesystem`
* 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
@ -1065,10 +771,10 @@ to the expected behavior.
`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
the methods depth() and pop() had issues and the copy behaviour and
`input_iterator_tag` conformance was broken, added tests
* Restructured some CMake code into a macro to ease the support for
C++17 `std::filesystem` builds of tests and examples for interoperability
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`
@ -1153,7 +859,7 @@ to the expected behavior.
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.
* 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.
@ -1166,7 +872,7 @@ to the expected behavior.
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.
and dereferencable 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.
@ -1175,5 +881,5 @@ to the expected behavior.
### [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.
C++17 std::filesystem, as far as possible without other C++17 dependencies.

View File

@ -1,5 +1,6 @@
macro(AddExecutableWithStdFS targetName)
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0))
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)
@ -11,7 +12,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND (CMAKE_CXX_COMPILER_VERSION V
target_link_libraries(${targetName} -lc++fs)
else()
target_compile_options(${targetName} PRIVATE "-stdlib=libc++")
target_link_libraries(${targetName} -stdlib=libc++ -lc++fs $<$<PLATFORM_ID:Linux>:rt>)
target_link_libraries(${targetName} -stdlib=libc++ -lc++fs)
endif()
else()
if(NOT APPLE)
@ -19,12 +20,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND (CMAKE_CXX_COMPILER_VERSION V
target_link_libraries(${targetName} -stdlib=libc++)
endif()
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test network)
endif()
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
@ -34,13 +29,6 @@ if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 O
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
target_link_libraries(${targetName} -lstdc++fs)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(${targetName} xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(${targetName} network)
endif()
target_compile_options(${targetName} PRIVATE $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>)
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
@ -58,19 +46,11 @@ 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)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test_cpp${cppStd} xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test_cpp${cppStd} network)
endif()
target_compile_options(filesystem_test_cpp${cppStd} PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-error=deprecated-declarations>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-error=deprecated-declarations>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror -Wno-error=deprecated-declarations>
$<$<CXX_COMPILER_ID:MSVC>:/WX /wd4996>
$<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>
$<$<BOOL:${GHC_COVERAGE}>:--coverage>)
$<$<CXX_COMPILER_ID:MSVC>:/WX /wd"4996">)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test_cpp${cppStd} PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()

View File

@ -1,6 +1,5 @@
@PACKAGE_INIT@
# import targets
include("${CMAKE_CURRENT_LIST_DIR}/ghc_filesystem-targets.cmake")
set_and_check(ghcfilesystem_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@")
check_required_components(ghcfilesystem)

View File

@ -10,8 +10,3 @@ 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()

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_fwd.hpp - The forwarding header for the header/implementation separated usage of
// 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,
@ -34,5 +34,5 @@
#ifndef GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD
#include "filesystem.hpp"
#include <ghc/filesystem.hpp>
#endif // GHC_FILESYSTEM_FWD_H

View File

@ -25,11 +25,11 @@
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_impl.hpp - The implementation header for the header/implementation separated usage of
// 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 "filesystem.hpp"
#include <ghc/filesystem.hpp>

View File

@ -30,48 +30,27 @@
// namespace fs.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_H
#define GHC_FILESYSTEM_STD_H
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "filesystem.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#include <ghc/filesystem.hpp>
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

View File

@ -25,7 +25,7 @@
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_std_fwd.hpp - The forwarding header for the header/implementation separated usage of
// 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,
@ -33,47 +33,28 @@
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_FWD_H
#define GHC_FILESYSTEM_STD_FWD_H
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "fs_fwd.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
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

View File

@ -25,36 +25,19 @@
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_std_impl.hpp - The implementation header for the header/implementation separated usage of
// 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(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!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
#include "fs_impl.hpp"
#define GHC_WIN_WSTRING_STRING_TYPE
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif

View File

@ -3,20 +3,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON)
include(ParseAndAddCatchTests)
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND UNIX AND NOT APPLE AND NOT BSD)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
set(CMAKE_EXE_LINKER_FLAGS "-lc++abi")
endif()
function(SetTestCompileOptions target_name)
target_compile_options(${target_name} PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-deprecated-declarations>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror -Wno-deprecated-declarations>
$<$<CXX_COMPILER_ID:MSVC>:/WX /wd4996>
$<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>)
endfunction()
if(GHC_COVERAGE)
message("Generating test runner for coverage run...")
set(CMAKE_EXE_LINKER_FLAGS "${CMCMAKE_EXE_LINKER_FLAGS} --coverage")
@ -27,54 +13,41 @@ if(GHC_COVERAGE)
target_compile_options(filesystem_test PUBLIC --coverage)
endif()
target_link_libraries(filesystem_test PUBLIC ghc_filesystem --coverage)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test PUBLIC xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test PUBLIC network)
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()
else()
message("Generating test runner for normal test...")
add_executable(filesystem_test filesystem_test.cpp catch.hpp)
target_link_libraries(filesystem_test ghc_filesystem)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test network)
endif()
SetTestCompileOptions(filesystem_test)
target_compile_options(filesystem_test PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX)
target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS)
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)
SetTestCompileOptions(filesystem_test_char)
add_executable(filesystem_test_wchar filesystem_test.cpp catch.hpp)
target_link_libraries(filesystem_test_wchar ghc_filesystem)
target_compile_options(filesystem_test_wchar PRIVATE
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/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)
target_compile_definitions(filesystem_test_wchar PRIVATE _CRT_SECURE_NO_WARNINGS GHC_WIN_WSTRING_STRING_TYPE)
else()
target_compile_definitions(filesystem_test_char PRIVATE GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE)
target_compile_definitions(filesystem_test_wchar PRIVATE GHC_WIN_WSTRING_STRING_TYPE)
endif()
ParseAndAddCatchTests(filesystem_test_char)
ParseAndAddCatchTests(filesystem_test_wchar)
endif()
if("cxx_std_17" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
if("cxx_std_17" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp)
endif()
if("cxx_std_20" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
if("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
AddTestExecutableWithStdCpp(20 filesystem_test.cpp catch.hpp)
endif()
endif()
@ -85,15 +58,8 @@ 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)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(fwd_impl_test xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(fwd_impl_test network)
endif()
SetTestCompileOptions(fwd_impl_test)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX)
target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
add_test(fwd_impl_test fwd_impl_test)
@ -102,4 +68,3 @@ if(NOT MSVC)
target_compile_options(exception PRIVATE -fno-exceptions)
endif()
target_include_directories(exception PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include)
SetTestCompileOptions(exception)

File diff suppressed because it is too large Load Diff

View File

@ -76,7 +76,6 @@ using fstream = ghc::filesystem::fstream;
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#endif
#ifndef GHC_FILESYSTEM_FWD_TEST
@ -99,7 +98,7 @@ using fstream = ghc::filesystem::fstream;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template <typename TP>
static std::time_t to_time_t(TP tp)
std::time_t to_time_t(TP tp)
{
using namespace std::chrono;
auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now());
@ -107,7 +106,7 @@ static std::time_t to_time_t(TP tp)
}
template <typename TP>
static TP from_time_t(std::time_t t)
TP from_time_t(std::time_t t)
{
using namespace std::chrono;
auto sctp = system_clock::from_time_t(t);
@ -128,14 +127,6 @@ struct StringMaker<fs::perms>
static std::string convert(fs::perms const& value) { return std::to_string(static_cast<unsigned int>(value)); }
};
template <>
struct StringMaker<fs::file_status>
{
static std::string convert(fs::file_status const& value) {
return std::string("[") + std::to_string(static_cast<unsigned int>(value.type())) + "," + std::to_string(static_cast<unsigned int>(value.permissions())) + "]";
}
};
#ifdef __cpp_lib_char8_t
template <>
struct StringMaker<char8_t>
@ -214,8 +205,7 @@ static void generateFile(const fs::path& pathname, int withSize = -1)
}
#ifdef GHC_OS_WINDOWS
#if !defined(_WIN64) && defined(KEY_WOW64_64KEY)
static bool isWow64Proc()
inline bool isWow64Proc()
{
typedef BOOL(WINAPI * IsWow64Process_t)(HANDLE, PBOOL);
BOOL bIsWow64 = FALSE;
@ -227,7 +217,6 @@ static bool isWow64Proc()
}
return bIsWow64 == TRUE;
}
#endif
static bool is_symlink_creation_supported()
{
@ -305,13 +294,13 @@ public:
};
template <class T, class U>
static bool operator==(TestAllocator<T> const&, TestAllocator<U> const&) noexcept
bool operator==(TestAllocator<T> const&, TestAllocator<U> const&) noexcept
{
return true;
}
template <class T, class U>
static bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept
bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept
{
return !(x == y);
}
@ -365,7 +354,7 @@ TEST_CASE("fs::detail::toUtf8", "[filesystem][fs.detail.utf8]")
}
#endif
TEST_CASE("fs.path.generic - path::preferred_separator", "[filesystem][path][fs.path.generic]")
TEST_CASE("30.10.8.1 path::preferred_separator", "[filesystem][path][fs.path.generic]")
{
#ifdef GHC_OS_WINDOWS
CHECK(fs::path::preferred_separator == '\\');
@ -375,7 +364,7 @@ TEST_CASE("fs.path.generic - path::preferred_separator", "[filesystem][path][fs.
}
#ifndef GHC_OS_WINDOWS
TEST_CASE("fs.path.generic - path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]")
TEST_CASE("30.10.8.1 path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]")
{
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.)");
@ -383,26 +372,15 @@ TEST_CASE("fs.path.generic - path(\"//host\").has_root_name()", "[filesystem][pa
}
#endif
TEST_CASE("fs.path.construct - path constructors and destructor", "[filesystem][path][fs.path.construct]")
TEST_CASE("30.10.8.4.1 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
@ -419,7 +397,7 @@ TEST_CASE("fs.path.construct - path constructors and destructor", "[filesystem][
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)
#if !defined(GHC_OS_WINDOWS) && !(defined(GCC_VERSION) && GCC_VERSION < 80100) && !defined(USE_STD_FS)
std::locale loc;
bool testUTF8Locale = false;
try {
@ -446,7 +424,7 @@ TEST_CASE("fs.path.construct - path constructors and destructor", "[filesystem][
#endif
}
TEST_CASE("fs.path.assign - path assignments", "[filesystem][path][fs.path.assign]")
TEST_CASE("30.10.8.4.2 path assignments", "[filesystem][path][fs.path.assign]")
{
fs::path p1{"/foo/bar"};
fs::path p2{"/usr/local"};
@ -455,10 +433,6 @@ TEST_CASE("fs.path.assign - path assignments", "[filesystem][path][fs.path.assig
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);
@ -481,7 +455,7 @@ TEST_CASE("fs.path.assign - path assignments", "[filesystem][path][fs.path.assig
REQUIRE(p2 == p3);
}
TEST_CASE("fs.path.append - path appends", "[filesystem][path][fs.path.append]")
TEST_CASE("30.10.8.4.3 path appends", "[filesystem][path][fs.path.append]")
{
#ifdef GHC_OS_WINDOWS
CHECK(fs::path("foo") / "c:/bar" == "c:/bar");
@ -507,7 +481,7 @@ TEST_CASE("fs.path.append - path appends", "[filesystem][path][fs.path.append]")
// TODO: append(first, last)
}
TEST_CASE("fs.path.concat - path concatenation", "[filesystem][path][fs.path.concat]")
TEST_CASE("30.10.8.4.4 path concatenation", "[filesystem][path][fs.path.concat]")
{
CHECK((fs::path("foo") += fs::path("bar")) == "foobar");
CHECK((fs::path("foo") += fs::path("/bar")) == "foo/bar");
@ -517,13 +491,9 @@ TEST_CASE("fs.path.concat - path concatenation", "[filesystem][path][fs.path.con
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");
@ -536,8 +506,6 @@ TEST_CASE("fs.path.concat - path concatenation", "[filesystem][path][fs.path.con
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
@ -546,7 +514,7 @@ TEST_CASE("fs.path.concat - path concatenation", "[filesystem][path][fs.path.con
// TODO: contat(first, last)
}
TEST_CASE("fs.path.modifiers - path modifiers", "[filesystem][path][fs.path.modifiers]")
TEST_CASE("30.10.8.4.5 path modifiers", "[filesystem][path][fs.path.modifiers]")
{
fs::path p = fs::path("/foo/bar");
p.clear();
@ -585,7 +553,7 @@ TEST_CASE("fs.path.modifiers - path modifiers", "[filesystem][path][fs.path.modi
CHECK(p2 == "foo");
}
TEST_CASE("fs.path.native.obs - path native format observers", "[filesystem][path][fs.path.native.obs]")
TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.path.native.obs]")
{
#ifdef GHC_OS_WINDOWS
#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
@ -623,7 +591,7 @@ TEST_CASE("fs.path.native.obs - path native format observers", "[filesystem][pat
#endif
}
TEST_CASE("fs.path.generic.obs - path generic format observers", "[filesystem][path][fs.path.generic.obs]")
TEST_CASE("30.10.8.4.7 path generic format observers", "[filesystem][path][fs.path.generic.obs]")
{
#ifdef GHC_OS_WINDOWS
#ifndef IS_WCHAR_PATH
@ -658,7 +626,7 @@ TEST_CASE("fs.path.generic.obs - path generic format observers", "[filesystem][p
#endif
}
TEST_CASE("fs.path.compare - path compare", "[filesystem][path][fs.path.compare]")
TEST_CASE("30.10.8.4.8 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);
@ -684,7 +652,7 @@ TEST_CASE("fs.path.compare - path compare", "[filesystem][path][fs.path.compare]
#endif // LWG_2936_BEHAVIOUR
}
TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.decompose]")
TEST_CASE("30.10.8.4.9 path decomposition", "[filesystem][path][fs.path.decompose]")
{
// root_name()
CHECK(fs::path("").root_name() == "");
@ -792,9 +760,6 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
CHECK(fs::path("C:/foo").filename() == "foo");
CHECK(fs::path("C:\\foo").filename() == "foo");
CHECK(fs::path("C:foo").filename() == "foo");
CHECK(fs::path("t:est.txt").filename() == "est.txt");
#else
CHECK(fs::path("t:est.txt").filename() == "t:est.txt");
#endif
// stem()
@ -812,13 +777,6 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
CHECK(fs::path("/foo/.profile").stem() == ".profile");
CHECK(fs::path(".bar").stem() == ".bar");
CHECK(fs::path("..bar").stem() == ".");
#ifdef GHC_OS_WINDOWS
CHECK(fs::path("t:est.txt").stem() == "est");
#else
CHECK(fs::path("t:est.txt").stem() == "t:est");
#endif
CHECK(fs::path("/foo/.").stem() == ".");
CHECK(fs::path("/foo/..").stem() == "..");
// extension()
CHECK(fs::path("/foo/bar.txt").extension() == ".txt");
@ -826,9 +784,6 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
CHECK(fs::path("/foo/.profile").extension() == "");
CHECK(fs::path(".bar").extension() == "");
CHECK(fs::path("..bar").extension() == ".bar");
CHECK(fs::path("t:est.txt").extension() == ".txt");
CHECK(fs::path("/foo/.").extension() == "");
CHECK(fs::path("/foo/..").extension() == "");
if (has_host_root_name_support()) {
// //host-based root-names
@ -847,7 +802,7 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
}
}
TEST_CASE("fs.path.query - path query", "[fielsystem][path][fs.path.query]")
TEST_CASE("30.10.8.4.10 path query", "[fielsystem][path][fs.path.query]")
{
// empty
CHECK(fs::path("").empty());
@ -945,7 +900,7 @@ TEST_CASE("fs.path.query - path query", "[fielsystem][path][fs.path.query]")
}
}
TEST_CASE("fs.path.gen - path generation", "[filesystem][path][fs.path.gen]")
TEST_CASE("30.10.8.4.11 path generation", "[filesystem][path][fs.path.gen]")
{
// lexically_normal()
CHECK(fs::path("foo/./bar/..").lexically_normal() == "foo/");
@ -965,10 +920,6 @@ TEST_CASE("fs.path.gen - path generation", "[filesystem][path][fs.path.gen]")
// 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/d/..") == ".");
CHECK(fs::path("/a/b/c/").lexically_relative("/a/b/c/d/..") == ".");
CHECK(fs::path("").lexically_relative("/a/..") == "");
CHECK(fs::path("").lexically_relative("a/..") == ".");
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") == ".");
@ -1036,7 +987,7 @@ static std::string reverseIterateResult(const fs::path& path)
return result.str();
}
TEST_CASE("fs.path.itr - path iterators", "[filesystem][path][fs.path.itr]")
TEST_CASE("30.10.8.5 path iterators", "[filesystem][path][fs.path.itr]")
{
CHECK(iterateResult(fs::path()).empty());
CHECK("." == iterateResult(fs::path(".")));
@ -1119,7 +1070,7 @@ TEST_CASE("fs.path.itr - path iterators", "[filesystem][path][fs.path.itr]")
}
}
TEST_CASE("fs.path.nonmember - path non-member functions", "[filesystem][path][fs.path.nonmember]")
TEST_CASE("30.10.8.6 path non-member functions", "[filesystem][path][fs.path.nonmember]")
{
fs::path p1("foo/bar");
fs::path p2("some/other");
@ -1141,7 +1092,7 @@ TEST_CASE("fs.path.nonmember - path non-member functions", "[filesystem][path][f
CHECK(p1 / p2 == "some/other/foo/bar");
}
TEST_CASE("fs.path.io - path inserter and extractor", "[filesystem][path][fs.path.io]")
TEST_CASE("30.10.8.6.1 path inserter and extractor", "[filesystem][path][fs.path.io]")
{
{
std::ostringstream os;
@ -1191,7 +1142,7 @@ TEST_CASE("fs.path.io - path inserter and extractor", "[filesystem][path][fs.pat
}
}
TEST_CASE("fs.path.factory - path factory functions", "[filesystem][path][fs.path.factory]")
TEST_CASE("30.10.8.6.2 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"));
@ -1199,7 +1150,7 @@ TEST_CASE("fs.path.factory - path factory functions", "[filesystem][path][fs.pat
CHECK(fs::u8path(str.begin(), str.end()) == str);
}
TEST_CASE("fs.class.filesystem_error - class filesystem_error", "[filesystem][filesystem_error][fs.class.filesystem_error]")
TEST_CASE("30.10.9 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());
@ -1218,12 +1169,12 @@ TEST_CASE("fs.class.filesystem_error - class filesystem_error", "[filesystem][fi
CHECK(fse.path2() == "some/other");
}
static constexpr fs::perms constExprOwnerAll()
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]")
TEST_CASE("30.10.10.4 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);
@ -1233,7 +1184,7 @@ TEST_CASE("fs.enum - enum class perms", "[filesystem][enum][fs.enum]")
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]")
TEST_CASE("30.10.11 class file_status", "[filesystem][file_status][fs.class.file_status]")
{
{
fs::file_status fs;
@ -1268,20 +1219,9 @@ TEST_CASE("fs.class.file_status - class file_status", "[filesystem][file_status]
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]")
TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.dir.entry]")
{
TemporaryDirectory t;
std::error_code ec;
@ -1396,19 +1336,9 @@ TEST_CASE("fs.dir.entry - class directory_entry", "[filesystem][directory_entry]
CHECK(!(d2 != d2));
CHECK(d1 == d1);
CHECK(!(d1 == d2));
if(is_symlink_creation_supported()) {
fs::create_symlink(t.path() / "nonexistent", t.path() / "broken");
for (auto d3 : fs::directory_iterator(t.path())) {
CHECK_NOTHROW(d3.symlink_status());
CHECK_NOTHROW(d3.status());
CHECK_NOTHROW(d3.refresh());
}
fs::directory_entry entry(t.path() / "broken");
CHECK_NOTHROW(entry.refresh());
}
}
TEST_CASE("fs.class.directory_iterator - class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]")
TEST_CASE("30.10.13 class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]")
{
{
TemporaryDirectory t;
@ -1469,7 +1399,7 @@ TEST_CASE("fs.class.directory_iterator - class directory_iterator", "[filesystem
}
}
TEST_CASE("fs.class.rec.dir.itr - class recursive_directory_iterator", "[filesystem][recursive_directory_iterator][fs.class.rec.dir.itr]")
TEST_CASE("30.10.14 class recursive_directory_iterator", "[filesystem][recursive_directory_iterator][fs.class.rec.dir.itr]")
{
{
auto iter = fs::recursive_directory_iterator(".");
@ -1625,40 +1555,9 @@ TEST_CASE("fs.class.rec.dir.itr - class recursive_directory_iterator", "[filesys
}
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<std::string> 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]")
TEST_CASE("30.10.15.1 absolute", "[filesystem][operations][fs.op.absolute]")
{
CHECK(fs::absolute("") == fs::current_path() / "");
CHECK(fs::absolute(fs::current_path()) == fs::current_path());
@ -1672,7 +1571,7 @@ TEST_CASE("fs.op.absolute - absolute", "[filesystem][operations][fs.op.absolute]
CHECK(!ec);
}
TEST_CASE("fs.op.canonical - canonical", "[filesystem][operations][fs.op.canonical]")
TEST_CASE("30.10.15.2 canonical", "[filesystem][operations][fs.op.canonical]")
{
CHECK_THROWS_AS(fs::canonical(""), fs::filesystem_error);
{
@ -1715,7 +1614,7 @@ TEST_CASE("fs.op.canonical - canonical", "[filesystem][operations][fs.op.canonic
}
}
TEST_CASE("fs.op.copy - copy", "[filesystem][operations][fs.op.copy]")
TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]")
{
{
TemporaryDirectory t(TempOpt::change_path);
@ -1784,7 +1683,7 @@ TEST_CASE("fs.op.copy - copy", "[filesystem][operations][fs.op.copy]")
#endif
}
TEST_CASE("fs.op.copy_file - copy_file", "[filesystem][operations][fs.op.copy_file]")
TEST_CASE("30.10.15.4 copy_file", "[filesystem][operations][fs.op.copy_file]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -1807,22 +1706,9 @@ TEST_CASE("fs.op.copy_file - copy_file", "[filesystem][operations][fs.op.copy_fi
CHECK_NOTHROW(fs::copy_file("foobar", "foobar2", ec));
CHECK(ec);
CHECK(!fs::exists("foobar"));
fs::path file1("temp1.txt");
fs::path file2("temp2.txt");
generateFile(file1, 200);
generateFile(file2, 200);
auto allWrite = fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write;
CHECK_NOTHROW(fs::permissions(file1, allWrite, fs::perm_options::remove));
CHECK((fs::status(file1).permissions() & fs::perms::owner_write) != fs::perms::owner_write);
CHECK_NOTHROW(fs::permissions(file2, allWrite, fs::perm_options::add));
CHECK((fs::status(file2).permissions() & fs::perms::owner_write) == fs::perms::owner_write);
fs::copy_file(file1, file2, fs::copy_options::overwrite_existing);
CHECK((fs::status(file2).permissions() & fs::perms::owner_write) != fs::perms::owner_write);
CHECK_NOTHROW(fs::permissions(file1, allWrite, fs::perm_options::add));
CHECK_NOTHROW(fs::permissions(file2, allWrite, fs::perm_options::add));
}
TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.copy_symlink]")
TEST_CASE("30.10.15.5 copy_symlink", "[filesystem][operations][fs.op.copy_symlink]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -1847,7 +1733,7 @@ TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.c
CHECK(ec);
}
TEST_CASE("fs.op.create_directories - create_directories", "[filesystem][operations][fs.op.create_directories]")
TEST_CASE("30.10.15.6 create_directories", "[filesystem][operations][fs.op.create_directories]")
{
TemporaryDirectory t;
fs::path p = t.path() / "testdir";
@ -1894,7 +1780,7 @@ TEST_CASE("fs.op.create_directories - create_directories", "[filesystem][operati
#endif
}
TEST_CASE("fs.op.create_directory - create_directory", "[filesystem][operations][fs.op.create_directory]")
TEST_CASE("30.10.15.7 create_directory", "[filesystem][operations][fs.op.create_directory]")
{
TemporaryDirectory t;
fs::path p = t.path() / "testdir";
@ -1941,7 +1827,7 @@ TEST_CASE("fs.op.create_directory - create_directory", "[filesystem][operations]
#endif
}
TEST_CASE("fs.op.create_directory_symlink - create_directory_symlink", "[filesystem][operations][fs.op.create_directory_symlink]")
TEST_CASE("30.10.15.8 create_directory_symlink", "[filesystem][operations][fs.op.create_directory_symlink]")
{
if (is_symlink_creation_supported()) {
TemporaryDirectory t;
@ -1960,7 +1846,7 @@ TEST_CASE("fs.op.create_directory_symlink - create_directory_symlink", "[filesys
}
}
TEST_CASE("fs.op.create_hard_link - create_hard_link", "[filesystem][operations][fs.op.create_hard_link]")
TEST_CASE("30.10.15.9 create_hard_link", "[filesystem][operations][fs.op.create_hard_link]")
{
#ifndef GHC_OS_WEB
TemporaryDirectory t(TempOpt::change_path);
@ -1979,7 +1865,7 @@ TEST_CASE("fs.op.create_hard_link - create_hard_link", "[filesystem][operations]
#endif
}
TEST_CASE("fs.op.create_symlink - create_symlink", "[filesystem][operations][fs.op.create_symlink]")
TEST_CASE("30.10.15.10 create_symlink", "[filesystem][operations][fs.op.create_symlink]")
{
if (is_symlink_creation_supported()) {
TemporaryDirectory t;
@ -1998,7 +1884,7 @@ TEST_CASE("fs.op.create_symlink - create_symlink", "[filesystem][operations][fs.
}
}
TEST_CASE("fs.op.current_path - current_path", "[filesystem][operations][fs.op.current_path]")
TEST_CASE("30.10.15.11 current_path", "[filesystem][operations][fs.op.current_path]")
{
TemporaryDirectory t;
std::error_code ec;
@ -2013,7 +1899,7 @@ TEST_CASE("fs.op.current_path - current_path", "[filesystem][operations][fs.op.c
CHECK(ec);
}
TEST_CASE("fs.op.equivalent - equivalent", "[filesystem][operations][fs.op.equivalent]")
TEST_CASE("30.10.15.12 equivalent", "[filesystem][operations][fs.op.equivalent]")
{
TemporaryDirectory t(TempOpt::change_path);
generateFile("foo", 1234);
@ -2067,7 +1953,7 @@ TEST_CASE("fs.op.equivalent - equivalent", "[filesystem][operations][fs.op.equiv
#endif
}
TEST_CASE("fs.op.exists - exists", "[filesystem][operations][fs.op.exists]")
TEST_CASE("30.10.15.13 exists", "[filesystem][operations][fs.op.exists]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2077,9 +1963,6 @@ TEST_CASE("fs.op.exists - exists", "[filesystem][operations][fs.op.exists]")
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()));
@ -2095,7 +1978,7 @@ TEST_CASE("fs.op.exists - exists", "[filesystem][operations][fs.op.exists]")
#endif
}
TEST_CASE("fs.op.file_size - file_size", "[filesystem][operations][fs.op.file_size]")
TEST_CASE("30.10.15.14 file_size", "[filesystem][operations][fs.op.file_size]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2117,16 +2000,7 @@ TEST_CASE("fs.op.file_size - file_size", "[filesystem][operations][fs.op.file_si
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]")
TEST_CASE("30.10.15.15 hard_link_count", "[filesystem][operations][fs.op.hard_link_count]")
{
#ifndef GHC_OS_WEB
TemporaryDirectory t(TempOpt::change_path);
@ -2141,9 +2015,9 @@ TEST_CASE("fs.op.hard_link_count - hard_link_count", "[filesystem][operations][f
// 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()));
CHECK(fs::hard_link_count(t.path()) == 2);
fs::create_directory("dir");
CHECK(fs::hard_link_count(t.path()) == getHardlinkCount(t.path()));
CHECK(fs::hard_link_count(t.path()) == 3);
#endif
generateFile("foo");
CHECK(fs::hard_link_count(t.path() / "foo") == 1);
@ -2205,7 +2079,6 @@ public:
fs::path character_path() const
{
#ifndef GHC_OS_SOLARIS
std::error_code ec;
if (fs::exists("/dev/null", ec)) {
return "/dev/null";
@ -2213,7 +2086,6 @@ public:
else if (fs::exists("NUL", ec)) {
return "NUL";
}
#endif
return fs::path();
}
fs::path temp_path() const { return _t.path(); }
@ -2224,7 +2096,7 @@ private:
bool _hasSocket;
};
TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_block_file - is_block_file", "[filesystem][operations][fs.op.is_block_file]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.16 is_block_file", "[filesystem][operations][fs.op.is_block_file]")
{
std::error_code ec;
CHECK(!fs::is_block_file("directory"));
@ -2253,7 +2125,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_block_file - is_block_file", "[fi
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]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.17 is_character_file", "[filesystem][operations][fs.op.is_character_file]")
{
std::error_code ec;
CHECK(!fs::is_character_file("directory"));
@ -2282,7 +2154,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_character_file - is_character_fil
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]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.18 is_directory", "[filesystem][operations][fs.op.is_directory]")
{
std::error_code ec;
CHECK(fs::is_directory("directory"));
@ -2311,7 +2183,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_directory - is_directory", "[file
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]")
TEST_CASE("30.10.15.19 is_empty", "[filesystem][operations][fs.op.is_empty]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2333,7 +2205,7 @@ TEST_CASE("fs.op.is_empty - is_empty", "[filesystem][operations][fs.op.is_empty]
CHECK(ec);
}
TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_fifo - is_fifo", "[filesystem][operations][fs.op.is_fifo]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.20 is_fifo", "[filesystem][operations][fs.op.is_fifo]")
{
std::error_code ec;
CHECK(!fs::is_fifo("directory"));
@ -2362,7 +2234,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_fifo - is_fifo", "[filesystem][op
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]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.21 is_other", "[filesystem][operations][fs.op.is_other]")
{
std::error_code ec;
CHECK(!fs::is_other("directory"));
@ -2391,7 +2263,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_other - is_other", "[filesystem][
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]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.22 is_regular_file", "[filesystem][operations][fs.op.is_regular_file]")
{
std::error_code ec;
CHECK(!fs::is_regular_file("directory"));
@ -2420,7 +2292,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_regular_file - is_regular_file",
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]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.23 is_socket", "[filesystem][operations][fs.op.is_socket]")
{
std::error_code ec;
CHECK(!fs::is_socket("directory"));
@ -2449,7 +2321,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "fs.op.is_socket - is_socket", "[filesystem
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]")
TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.24 is_symlink", "[filesystem][operations][fs.op.is_symlink]")
{
std::error_code ec;
CHECK(!fs::is_symlink("directory"));
@ -2492,7 +2364,7 @@ static fs::file_time_type timeFromString(const std::string& str)
}
#endif
TEST_CASE("fs.op.last_write_time - last_write_time", "[filesystem][operations][fs.op.last_write_time]")
TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_write_time]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2527,7 +2399,7 @@ TEST_CASE("fs.op.last_write_time - last_write_time", "[filesystem][operations][f
#endif
}
TEST_CASE("fs.op.permissions - permissions", "[filesystem][operations][fs.op.permissions]")
TEST_CASE("30.10.15.26 permissions", "[filesystem][operations][fs.op.permissions]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2535,13 +2407,8 @@ TEST_CASE("fs.op.permissions - permissions", "[filesystem][operations][fs.op.per
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));
@ -2552,7 +2419,7 @@ TEST_CASE("fs.op.permissions - permissions", "[filesystem][operations][fs.op.per
CHECK_THROWS_AS(fs::permissions("bar", fs::perms::owner_write, static_cast<fs::perm_options>(0)), fs::filesystem_error);
}
TEST_CASE("fs.op.proximate - proximate", "[filesystem][operations][fs.op.proximate]")
TEST_CASE("30.10.15.27 proximate", "[filesystem][operations][fs.op.proximate]")
{
std::error_code ec;
CHECK(fs::proximate("/a/d", "/a/b/c") == "../../d");
@ -2582,7 +2449,7 @@ TEST_CASE("fs.op.proximate - proximate", "[filesystem][operations][fs.op.proxima
#endif
}
TEST_CASE("fs.op.read_symlink - read_symlink", "[filesystem][operations][fs.op.read_symlink]")
TEST_CASE("30.10.15.28 read_symlink", "[filesystem][operations][fs.op.read_symlink]")
{
if (is_symlink_creation_supported()) {
TemporaryDirectory t(TempOpt::change_path);
@ -2598,7 +2465,7 @@ TEST_CASE("fs.op.read_symlink - read_symlink", "[filesystem][operations][fs.op.r
}
}
TEST_CASE("fs.op.relative - relative", "[filesystem][operations][fs.op.relative]")
TEST_CASE("30.10.15.29 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");
@ -2611,7 +2478,7 @@ TEST_CASE("fs.op.relative - relative", "[filesystem][operations][fs.op.relative]
CHECK(!ec);
}
TEST_CASE("fs.op.remove - remove", "[filesystem][operations][fs.op.remove]")
TEST_CASE("30.10.15.30 remove", "[filesystem][operations][fs.op.remove]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2635,7 +2502,7 @@ TEST_CASE("fs.op.remove - remove", "[filesystem][operations][fs.op.remove]")
CHECK(!ec);
}
TEST_CASE("fs.op.remove_all - remove_all", "[filesystem][operations][fs.op.remove_all]")
TEST_CASE("30.10.15.31 remove_all", "[filesystem][operations][fs.op.remove_all]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2651,15 +2518,11 @@ TEST_CASE("fs.op.remove_all - remove_all", "[filesystem][operations][fs.op.remov
CHECK_NOTHROW(fs::remove_all("dir1/non-existing", ec));
CHECK(!ec);
CHECK(fs::remove_all("dir1/non-existing", ec) == 0);
if (is_symlink_creation_supported()) {
fs::create_directory_symlink("dir1", "dir1link");
CHECK(fs::remove_all("dir1link") == 1);
}
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]")
TEST_CASE("30.10.15.32 rename", "[filesystem][operations][fs.op.rename]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2683,7 +2546,7 @@ TEST_CASE("fs.op.rename - rename", "[filesystem][operations][fs.op.rename]")
CHECK(!fs::exists("barfoo"));
}
TEST_CASE("fs.op.resize_file - resize_file", "[filesystem][operations][fs.op.resize_file]")
TEST_CASE("30.10.15.33 resize_file", "[filesystem][operations][fs.op.resize_file]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2701,7 +2564,7 @@ TEST_CASE("fs.op.resize_file - resize_file", "[filesystem][operations][fs.op.res
CHECK(!fs::exists("bar"));
}
TEST_CASE("fs.op.space - space", "[filesystem][operations][fs.op.space]")
TEST_CASE("30.10.15.34 space", "[filesystem][operations][fs.op.space]")
{
{
fs::space_info si;
@ -2733,7 +2596,7 @@ TEST_CASE("fs.op.space - space", "[filesystem][operations][fs.op.space]")
#endif
}
TEST_CASE("fs.op.status - status", "[filesystem][operations][fs.op.status]")
TEST_CASE("30.10.15.35 status", "[filesystem][operations][fs.op.status]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2761,7 +2624,7 @@ TEST_CASE("fs.op.status - status", "[filesystem][operations][fs.op.status]")
}
}
TEST_CASE("fs.op.status_known - status_known", "[filesystem][operations][fs.op.status_known]")
TEST_CASE("30.10.15.36 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)));
@ -2774,7 +2637,7 @@ TEST_CASE("fs.op.status_known - status_known", "[filesystem][operations][fs.op.s
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]")
TEST_CASE("30.10.15.37 symlink_status", "[filesystem][operations][fs.op.symlink_status]")
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -2801,7 +2664,7 @@ TEST_CASE("fs.op.symlink_status - symlink_status", "[filesystem][operations][fs.
}
}
TEST_CASE("fs.op.temp_dir_path - temporary_directory_path", "[filesystem][operations][fs.op.temp_dir_path]")
TEST_CASE("30.10.15.38 temporary_directory_path", "[filesystem][operations][fs.op.temp_dir_path]")
{
std::error_code ec;
CHECK_NOTHROW(fs::exists(fs::temp_directory_path()));
@ -2810,7 +2673,7 @@ TEST_CASE("fs.op.temp_dir_path - temporary_directory_path", "[filesystem][operat
CHECK(!ec);
}
TEST_CASE("fs.op.weakly_canonical - weakly_canonical", "[filesystem][operations][fs.op.weakly_canonical]")
TEST_CASE("30.10.15.39 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("") == ".");
@ -2849,40 +2712,33 @@ TEST_CASE("fs.op.weakly_canonical - weakly_canonical", "[filesystem][operations]
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)
#if __cpp_lib_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);
std::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");
p2 += std::string_view("o");
CHECK(p2 == "foo");
CHECK(p2.compare(string_view("foo")) == 0);
CHECK(p2.compare(std::string_view("foo")) == 0);
}
{
auto p = fs::path{"XYZ"};
p /= string_view("Appendix");
p /= std::string_view("Appendix");
CHECK(p == "XYZ/Appendix");
}
#if defined(IS_WCHAR_PATH) || defined(GHC_USE_WCHAR_T)
{
std::wstring p(L"foo/bar");
wstring_view sv(p);
std::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");
p2 += std::wstring_view(L"o");
CHECK(p2 == "foo");
CHECK(p2.compare(wstring_view(L"foo")) == 0);
CHECK(p2.compare(std::wstring_view(L"foo")) == 0);
}
#endif
#else
WARN("std::string_view specific tests are empty without std::string_view.");
@ -2902,15 +2758,13 @@ TEST_CASE("Windows: Long filename support", "[filesystem][path][fs.path.win.long
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"));
auto native = dir.u8string();
if (native.substr(0, 4) == u8"\\\\?\\") {
break;
}
}
CHECK(c <= 'Z');
#else
WARN("Windows specific tests are empty on non-Windows systems.");
#endif
@ -2943,8 +2797,8 @@ TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.na
{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"},
{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"},
@ -2961,7 +2815,6 @@ TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.na
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);
@ -2970,31 +2823,3 @@ TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.na
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
}

View File

@ -3,6 +3,7 @@
// 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 NOMINMAX
#include <ghc/fs_impl.hpp>
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View File

@ -27,7 +27,7 @@
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
// This test and the one in multi2.cpp doesn't actually test relevant functionality,
// 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]")