Revert "[libc++] Build <filesystem> support as part of the dylib"

When I applied r356500 (https://reviews.llvm.org/D59152), I somehow
deleted all of filesystem's tests. I will revert r356500 and re-apply
it properly.

llvm-svn: 356505
This commit is contained in:
Louis Dionne 2019-03-19 19:27:29 +00:00
parent d81df259b3
commit f7b43230b8
163 changed files with 14305 additions and 210 deletions

View File

@ -73,6 +73,12 @@ option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." O
option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON)
option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON)
set(ENABLE_FILESYSTEM_DEFAULT ${LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY})
if (WIN32)
set(ENABLE_FILESYSTEM_DEFAULT OFF)
endif()
option(LIBCXX_ENABLE_FILESYSTEM "Build filesystem as part of libc++fs.a"
${ENABLE_FILESYSTEM_DEFAULT})
option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
# Benchmark options -----------------------------------------------------------
@ -111,6 +117,9 @@ option(LIBCXX_INSTALL_SUPPORT_HEADERS "Install libc++ support headers." ON)
cmake_dependent_option(LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY
"Install libc++experimental.a" ON
"LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY;LIBCXX_INSTALL_LIBRARY" OFF)
cmake_dependent_option(LIBCXX_INSTALL_FILESYSTEM_LIBRARY
"Install libc++fs.a" ON
"LIBCXX_ENABLE_FILESYSTEM;LIBCXX_INSTALL_LIBRARY" OFF)
set(LIBCXX_ABI_VERSION "1" CACHE STRING "ABI version of libc++. Can be either 1 or 2, where 2 is currently not stable. Defaults to 1.")
set(LIBCXX_ABI_NAMESPACE "" CACHE STRING "The inline ABI namespace used by libc++. It defaults to __n where `n` is the current ABI version.")
@ -282,6 +291,11 @@ option(LIBCXX_HERMETIC_STATIC_LIBRARY
# Check option configurations
#===============================================================================
if (LIBCXX_ENABLE_FILESYSTEM AND NOT LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
message(FATAL_ERROR
"LIBCXX_ENABLE_FILESYSTEM cannot be turned on when LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF")
endif()
# Ensure LIBCXX_ENABLE_MONOTONIC_CLOCK is set to ON only when
# LIBCXX_ENABLE_THREADS is on.
if(LIBCXX_ENABLE_THREADS AND NOT LIBCXX_ENABLE_MONOTONIC_CLOCK)
@ -777,6 +791,9 @@ set(LIBCXX_TEST_DEPS "")
if (LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
list(APPEND LIBCXX_TEST_DEPS cxx_experimental)
endif()
if (LIBCXX_ENABLE_FILESYSTEM)
list(APPEND LIBCXX_TEST_DEPS cxx_filesystem)
endif()
if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY)
list(APPEND LIBCXX_TEST_DEPS cxx_external_threads)

View File

@ -146,6 +146,9 @@ function(add_benchmark_test name source_file)
if (TARGET cxx_experimental)
target_link_libraries(${libcxx_target} cxx_experimental)
endif()
if (TARGET cxx_filesystem)
target_link_libraries(${libcxx_target} cxx_filesystem)
endif()
target_link_libraries(${libcxx_target} -lbenchmark)
if (LLVM_USE_SANITIZER)
target_link_libraries(${libcxx_target} -ldl)

View File

@ -224,6 +224,18 @@ libc++experimental Specific Options
Install libc++experimental.a alongside libc++.
.. option:: LIBCXX_ENABLE_FILESYSTEM:BOOL
**Default**: ``ON``
Build filesystem as a standalone library libc++fs.a.
.. option:: LIBCXX_INSTALL_FILESYSTEM_LIBRARY:BOOL
**Default**: ``LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_INSTALL_LIBRARY``
Install libc++fs.a alongside libc++.
.. _ABI Library Specific Options:
ABI Library Specific Options

View File

@ -50,6 +50,23 @@ An example of using ``LD_LIBRARY_PATH``:
$ ./a.out # Searches for libc++ along LD_LIBRARY_PATH
Using ``<filesystem>`` and libc++fs
====================================
Libc++ provides the implementation of the filesystem library in a separate
library. Users of ``<filesystem>`` and ``<experimental/filesystem>`` are
required to link ``-lc++fs``.
.. note::
Prior to libc++ 7.0, users of ``<experimental/filesystem>`` were required
to link libc++experimental.
.. warning::
The Filesystem library is still experimental in nature. As such normal
guarantees about ABI stability and backwards compatibility do not yet apply
to it. In the future, this restriction will be removed.
Using libc++experimental and ``<experimental/...>``
=====================================================
@ -66,6 +83,9 @@ installed. For information on building libc++experimental from source see
:ref:`Building Libc++ <build instructions>` and
:ref:`libc++experimental CMake Options <libc++experimental options>`.
Note that as of libc++ 7.0 using the ``<experimental/filesystem>`` requires linking
libc++fs instead of libc++experimental.
Also see the `Experimental Library Implementation Status <http://libcxx.llvm.org/ts1z_status.html>`__
page.

View File

@ -3,8 +3,6 @@ set(LIBCXX_LIB_CMAKEFILES_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTOR
# Get sources
# FIXME: Don't use glob here
file(GLOB LIBCXX_SOURCES ../src/*.cpp)
list(APPEND LIBCXX_SOURCES ../src/filesystem/operations.cpp
../src/filesystem/directory_iterator.cpp)
if(WIN32)
file(GLOB LIBCXX_WIN32_SOURCES ../src/support/win32/*.cpp)
list(APPEND LIBCXX_SOURCES ${LIBCXX_WIN32_SOURCES})
@ -13,14 +11,6 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
list(APPEND LIBCXX_SOURCES ${LIBCXX_SOLARIS_SOURCES})
endif()
# Filesystem uses __int128_t, which requires a definition of __muloi4 when
# compiled with UBSAN. This definition is not provided by libgcc_s, but is
# provided by compiler-rt. So we need to disable it to avoid having multiple
# definitions. See filesystem/int128_builtins.cpp.
if (NOT LIBCXX_USE_COMPILER_RT)
list(APPEND LIBCXX_SOURCES ../src/filesystem/int128_builtins.cpp)
endif()
# Add all the headers to the project for IDEs.
if (LIBCXX_CONFIGURE_IDE)
file(GLOB_RECURSE LIBCXX_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/*)
@ -288,6 +278,39 @@ endif()
# Add a meta-target for both libraries.
add_custom_target(cxx DEPENDS cxx-headers ${LIBCXX_BUILD_TARGETS})
if (LIBCXX_ENABLE_FILESYSTEM)
set(LIBCXX_FILESYSTEM_SOURCES
../src/filesystem/operations.cpp
../src/filesystem/directory_iterator.cpp)
# Filesystem uses __int128_t, which requires a definition of __muloi4 when
# compiled with UBSAN. This definition is not provided by libgcc_s, but is
# provided by compiler-rt. So we need to disable it to avoid having multiple
# definitions. See filesystem/int128_builtins.cpp.
if (NOT LIBCXX_USE_COMPILER_RT)
list(APPEND LIBCXX_FILESYSTEM_SOURCES ../src/filesystem/int128_builtins.cpp)
endif()
add_library(cxx_filesystem STATIC ${LIBCXX_FILESYSTEM_SOURCES})
if (LIBCXX_ENABLE_SHARED)
target_link_libraries(cxx_filesystem cxx_shared)
else()
target_link_libraries(cxx_filesystem cxx_static)
endif()
set(filesystem_flags "${LIBCXX_COMPILE_FLAGS}")
check_flag_supported(-std=c++14)
if (NOT MSVC AND LIBCXX_SUPPORTS_STD_EQ_CXX14_FLAG AND LIBCXX_STANDARD_VER STREQUAL "c++11")
string(REPLACE "-std=c++11" "-std=c++14" filesystem_flags "${LIBCXX_COMPILE_FLAGS}")
endif()
set_target_properties(cxx_filesystem
PROPERTIES
COMPILE_FLAGS "${filesystem_flags}"
OUTPUT_NAME "c++fs"
)
endif()
if (LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
file(GLOB LIBCXX_EXPERIMENTAL_SOURCES ../src/experimental/*.cpp)
add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES})
@ -356,10 +379,13 @@ if (LIBCXX_ENABLE_SHARED AND LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
endif()
if (LIBCXX_INSTALL_LIBRARY)
if (LIBCXX_INSTALL_FILESYSTEM_LIBRARY)
set(filesystem_lib cxx_filesystem)
endif()
if (LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY)
set(experimental_lib cxx_experimental)
endif()
install(TARGETS ${LIBCXX_INSTALL_TARGETS} ${experimental_lib}
install(TARGETS ${LIBCXX_INSTALL_TARGETS} ${filesystem_lib} ${experimental_lib}
LIBRARY DESTINATION ${LIBCXX_INSTALL_PREFIX}lib${LIBCXX_LIBDIR_SUFFIX} COMPONENT cxx
ARCHIVE DESTINATION ${LIBCXX_INSTALL_PREFIX}lib${LIBCXX_LIBDIR_SUFFIX} COMPONENT cxx
)
@ -379,6 +405,9 @@ if (NOT CMAKE_CONFIGURATION_TYPES AND (LIBCXX_INSTALL_LIBRARY OR
if(LIBCXX_INSTALL_LIBRARY)
set(lib_install_target cxx)
endif()
if (LIBCXX_INSTALL_FILESYSTEM_LIBRARY)
set(filesystem_lib_install_target cxx_filesystem)
endif()
if (LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY)
set(experimental_lib_install_target cxx_experimental)
endif()
@ -388,6 +417,7 @@ if (NOT CMAKE_CONFIGURATION_TYPES AND (LIBCXX_INSTALL_LIBRARY OR
add_custom_target(install-cxx
DEPENDS ${lib_install_target}
${experimental_lib_install_target}
${filesystem_lib_install_target}
${header_install_target}
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=cxx
@ -395,6 +425,7 @@ if (NOT CMAKE_CONFIGURATION_TYPES AND (LIBCXX_INSTALL_LIBRARY OR
add_custom_target(install-cxx-stripped
DEPENDS ${lib_install_target}
${experimental_lib_install_target}
${filesystem_lib_install_target}
${header_install_target}
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=cxx

View File

@ -16,130 +16,6 @@ New entries should be added directly below the "Version" header.
Version 9.0
-----------
* rXXXXXX - Integrate <filesystem> support into the shared library
This patch introduces support for <filesystem> into the shared library,
instead of requiring users to manually link against a static archive. As
such, new symbols required to implement <filesystem> are exported from
the shared library.
x86_64-unknown-linux-gnu
------------------------
TODO
x86_64-apple-apple-darwin
-------------------------
Symbol added: __ZNKSt3__14__fs10filesystem18directory_iterator13__dereferenceEv
Symbol added: __ZNKSt3__14__fs10filesystem28recursive_directory_iterator13__dereferenceEv
Symbol added: __ZNKSt3__14__fs10filesystem28recursive_directory_iterator5depthEv
Symbol added: __ZNKSt3__14__fs10filesystem28recursive_directory_iterator7optionsEv
Symbol added: __ZNKSt3__14__fs10filesystem4path10__filenameEv
Symbol added: __ZNKSt3__14__fs10filesystem4path11__extensionEv
Symbol added: __ZNKSt3__14__fs10filesystem4path11__root_nameEv
Symbol added: __ZNKSt3__14__fs10filesystem4path13__parent_pathEv
Symbol added: __ZNKSt3__14__fs10filesystem4path15__relative_pathEv
Symbol added: __ZNKSt3__14__fs10filesystem4path15__root_path_rawEv
Symbol added: __ZNKSt3__14__fs10filesystem4path16__root_directoryEv
Symbol added: __ZNKSt3__14__fs10filesystem4path16lexically_normalEv
Symbol added: __ZNKSt3__14__fs10filesystem4path18lexically_relativeERKS2_
Symbol added: __ZNKSt3__14__fs10filesystem4path3endEv
Symbol added: __ZNKSt3__14__fs10filesystem4path5beginEv
Symbol added: __ZNKSt3__14__fs10filesystem4path6__stemEv
Symbol added: __ZNKSt3__14__fs10filesystem4path9__compareENS_17basic_string_viewIcNS_11char_traitsIcEEEE
Symbol added: __ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE
Symbol added: __ZNSt3__14__fs10filesystem11__canonicalERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem11__copy_fileERKNS1_4pathES4_NS1_12copy_optionsEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem11__file_sizeERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem12__equivalentERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem12__remove_allERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem13__fs_is_emptyERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem13__permissionsERKNS1_4pathENS1_5permsENS1_12perm_optionsEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem13__resize_fileERKNS1_4pathEmPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__copy_symlinkERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__current_pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__current_pathERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__read_symlinkERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem15directory_entry12__do_refreshEv
Symbol added: __ZNSt3__14__fs10filesystem16__create_symlinkERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem16__symlink_statusERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem16_FilesystemClock3nowEv
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_error13__create_whatEi
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_errorD0Ev
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_errorD1Ev
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_errorD2Ev
Symbol added: __ZNSt3__14__fs10filesystem17__hard_link_countERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem17__last_write_timeERKNS1_4pathENS_6chrono10time_pointINS1_16_FilesystemClockENS5_8durationInNS_5ratioILl1ELl1000000000EEEEEEEPNS_10error_codeE
Symbol added: __ZNKSt3__14__fs10filesystem28recursive_directory_iterator5depthEv
Symbol added: __ZNKSt3__14__fs10filesystem28recursive_directory_iterator7optionsEv
Symbol added: __ZNKSt3__14__fs10filesystem4path10__filenameEv
Symbol added: __ZNKSt3__14__fs10filesystem4path11__extensionEv
Symbol added: __ZNKSt3__14__fs10filesystem4path11__root_nameEv
Symbol added: __ZNKSt3__14__fs10filesystem4path13__parent_pathEv
Symbol added: __ZNKSt3__14__fs10filesystem4path15__relative_pathEv
Symbol added: __ZNKSt3__14__fs10filesystem4path15__root_path_rawEv
Symbol added: __ZNKSt3__14__fs10filesystem4path16__root_directoryEv
Symbol added: __ZNKSt3__14__fs10filesystem4path16lexically_normalEv
Symbol added: __ZNKSt3__14__fs10filesystem4path18lexically_relativeERKS2_
Symbol added: __ZNKSt3__14__fs10filesystem4path3endEv
Symbol added: __ZNKSt3__14__fs10filesystem4path5beginEv
Symbol added: __ZNKSt3__14__fs10filesystem4path6__stemEv
Symbol added: __ZNKSt3__14__fs10filesystem4path9__compareENS_17basic_string_viewIcNS_11char_traitsIcEEEE
Symbol added: __ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE
Symbol added: __ZNSt3__14__fs10filesystem11__canonicalERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem11__copy_fileERKNS1_4pathES4_NS1_12copy_optionsEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem11__file_sizeERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem12__equivalentERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem12__remove_allERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem13__fs_is_emptyERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem13__permissionsERKNS1_4pathENS1_5permsENS1_12perm_optionsEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem13__resize_fileERKNS1_4pathEmPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__copy_symlinkERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__current_pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__current_pathERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem14__read_symlinkERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem15directory_entry12__do_refreshEv
Symbol added: __ZNSt3__14__fs10filesystem16__create_symlinkERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem16__symlink_statusERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem16_FilesystemClock3nowEv
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_error13__create_whatEi
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_errorD0Ev
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_errorD1Ev
Symbol added: __ZNSt3__14__fs10filesystem16filesystem_errorD2Ev
Symbol added: __ZNSt3__14__fs10filesystem17__hard_link_countERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem17__last_write_timeERKNS1_4pathENS_6chrono10time_pointINS1_16_FilesystemClockENS5_8durationInNS_5ratioILl1ELl1000000000EEEEEEEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem17__last_write_timeERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem18__create_directoryERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem18__create_directoryERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem18__create_hard_linkERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem18__weakly_canonicalERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem18directory_iterator11__incrementEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem18directory_iteratorC1ERKNS1_4pathEPNS_10error_codeENS1_17directory_optionsE
Symbol added: __ZNSt3__14__fs10filesystem18directory_iteratorC2ERKNS1_4pathEPNS_10error_codeENS1_17directory_optionsE
Symbol added: __ZNSt3__14__fs10filesystem20__create_directoriesERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem21__temp_directory_pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem26__create_directory_symlinkERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem28recursive_directory_iterator11__incrementEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem28recursive_directory_iterator15__try_recursionEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem28recursive_directory_iterator5__popEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem28recursive_directory_iterator9__advanceEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem28recursive_directory_iteratorC1ERKNS1_4pathENS1_17directory_optionsEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem28recursive_directory_iteratorC2ERKNS1_4pathENS1_17directory_optionsEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem4path17replace_extensionERKS2_
Symbol added: __ZNSt3__14__fs10filesystem4path8iterator11__decrementEv
Symbol added: __ZNSt3__14__fs10filesystem4path8iterator11__incrementEv
Symbol added: __ZNSt3__14__fs10filesystem6__copyERKNS1_4pathES4_NS1_12copy_optionsEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem7__spaceERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem8__removeERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem8__renameERKNS1_4pathES4_PNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem8__statusERKNS1_4pathEPNS_10error_codeE
Symbol added: __ZNSt3__14__fs10filesystem16_FilesystemClock9is_steadyE
Symbol added: __ZNSt3__14__fs10filesystem4path19preferred_separatorE
Symbol added: __ZTINSt3__14__fs10filesystem16filesystem_errorE
Symbol added: __ZTSNSt3__14__fs10filesystem16filesystem_errorE
Symbol added: __ZTVNSt3__14__fs10filesystem16filesystem_errorE
* rTBD - Remove exception throwing debug mode handler support.
The reason libc++ implemented a throwing debug mode handler was for ease of testing. Specifically,

View File

@ -2346,74 +2346,3 @@
{'is_defined': True, 'name': '___dynamic_cast', 'type': 'I'}
{'is_defined': False, 'name': '___gxx_personality_v0', 'type': 'U'}
{'is_defined': True, 'name': '___gxx_personality_v0', 'type': 'I'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem18directory_iterator13__dereferenceEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem28recursive_directory_iterator13__dereferenceEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem28recursive_directory_iterator5depthEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem28recursive_directory_iterator7optionsEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path10__filenameEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path11__extensionEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path11__root_nameEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path13__parent_pathEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path15__relative_pathEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path15__root_path_rawEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path16__root_directoryEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path16lexically_normalEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path18lexically_relativeERKS2_'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path3endEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path5beginEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path6__stemEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNKSt3__14__fs10filesystem4path9__compareENS_17basic_string_viewIcNS_11char_traitsIcEEEE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10__absoluteERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem10hash_valueERKNS1_4pathE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem11__canonicalERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem11__copy_fileERKNS1_4pathES4_NS1_12copy_optionsEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem11__file_sizeERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem12__equivalentERKNS1_4pathES4_PNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem12__remove_allERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem13__fs_is_emptyERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem13__permissionsERKNS1_4pathENS1_5permsENS1_12perm_optionsEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem13__resize_fileERKNS1_4pathEmPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem14__copy_symlinkERKNS1_4pathES4_PNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem14__current_pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem14__current_pathERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem14__read_symlinkERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem15directory_entry12__do_refreshEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16__create_symlinkERKNS1_4pathES4_PNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16__symlink_statusERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16_FilesystemClock3nowEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16filesystem_error13__create_whatEi'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16filesystem_errorD0Ev'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16filesystem_errorD1Ev'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16filesystem_errorD2Ev'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem17__hard_link_countERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem17__last_write_timeERKNS1_4pathENS_6chrono10time_pointINS1_16_FilesystemClockENS5_8durationInNS_5ratioILl1ELl1000000000EEEEEEEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem17__last_write_timeERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem18__create_directoryERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem18__create_directoryERKNS1_4pathES4_PNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem18__create_hard_linkERKNS1_4pathES4_PNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem18__weakly_canonicalERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem18directory_iterator11__incrementEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem18directory_iteratorC1ERKNS1_4pathEPNS_10error_codeENS1_17directory_optionsE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem18directory_iteratorC2ERKNS1_4pathEPNS_10error_codeENS1_17directory_optionsE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem20__create_directoriesERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem21__temp_directory_pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem26__create_directory_symlinkERKNS1_4pathES4_PNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem28recursive_directory_iterator11__incrementEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem28recursive_directory_iterator15__try_recursionEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem28recursive_directory_iterator5__popEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem28recursive_directory_iterator9__advanceEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem28recursive_directory_iteratorC1ERKNS1_4pathENS1_17directory_optionsEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem28recursive_directory_iteratorC2ERKNS1_4pathENS1_17directory_optionsEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem4path17replace_extensionERKS2_'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem4path8iterator11__decrementEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem4path8iterator11__incrementEv'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem6__copyERKNS1_4pathES4_NS1_12copy_optionsEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem7__spaceERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem8__removeERKNS1_4pathEPNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem8__renameERKNS1_4pathES4_PNS_10error_codeE'}
{'type': 'FUNC', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem8__statusERKNS1_4pathEPNS_10error_codeE'}
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem16_FilesystemClock9is_steadyE', 'size': 0}
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZNSt3__14__fs10filesystem4path19preferred_separatorE', 'size': 0}
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZTINSt3__14__fs10filesystem16filesystem_errorE', 'size': 0}
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZTSNSt3__14__fs10filesystem16filesystem_errorE', 'size': 0}
{'type': 'OBJECT', 'is_defined': True, 'name': '__ZTVNSt3__14__fs10filesystem16filesystem_errorE', 'size': 0}

View File

@ -28,6 +28,7 @@ endif()
pythonize_bool(LIBCXX_ENABLE_EXCEPTIONS)
pythonize_bool(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
pythonize_bool(LIBCXX_ENABLE_FILESYSTEM)
pythonize_bool(LIBCXX_ENABLE_RTTI)
pythonize_bool(LIBCXX_ENABLE_SHARED)
pythonize_bool(LIBCXX_BUILD_32_BITS)

View File

@ -0,0 +1,3 @@
# Disable all of the filesystem tests if the correct feature is not available.
if 'c++filesystem' not in config.available_features:
config.unsupported = True

View File

@ -6,6 +6,7 @@ config.libcxx_obj_root = "@LIBCXX_BINARY_DIR@"
config.cxx_library_root = "@LIBCXX_LIBRARY_DIR@"
config.enable_exceptions = @LIBCXX_ENABLE_EXCEPTIONS@
config.enable_experimental = @LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY@
config.enable_filesystem = @LIBCXX_ENABLE_FILESYSTEM@
config.enable_rtti = @LIBCXX_ENABLE_RTTI@
config.enable_shared = @LIBCXX_ENABLE_SHARED@
config.enable_32bit = @LIBCXX_BUILD_32_BITS@

View File

@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

View File

@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

View File

@ -0,0 +1,73 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry(const directory_entry&) = default;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
#include "test_convertible.hpp"
TEST_SUITE(directory_entry_path_ctor_suite)
TEST_CASE(copy_ctor) {
using namespace fs;
// Copy
{
static_assert(std::is_copy_constructible<directory_entry>::value,
"directory_entry must be copy constructible");
static_assert(!std::is_nothrow_copy_constructible<directory_entry>::value,
"directory_entry's copy constructor cannot be noexcept");
const path p("foo/bar/baz");
const directory_entry e(p);
assert(e.path() == p);
directory_entry e2(e);
assert(e.path() == p);
assert(e2.path() == p);
}
}
TEST_CASE(copy_ctor_copies_cache) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym = env.create_symlink("dir/file", "sym");
{
directory_entry ent(sym);
fs::remove(sym);
directory_entry ent_cp(ent);
TEST_CHECK(ent_cp.path() == sym);
TEST_CHECK(ent_cp.is_symlink());
}
{
directory_entry ent(file);
fs::remove(file);
directory_entry ent_cp(ent);
TEST_CHECK(ent_cp.path() == file);
TEST_CHECK(ent_cp.is_regular_file());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry& operator=(directory_entry const&) = default;
// directory_entry& operator=(directory_entry&&) noexcept = default;
// void assign(path const&);
// void replace_filename(path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
TEST_SUITE(directory_entry_ctor_suite)
TEST_CASE(test_copy_assign_operator) {
using namespace fs;
// Copy
{
static_assert(std::is_copy_assignable<directory_entry>::value,
"directory_entry must be copy assignable");
static_assert(!std::is_nothrow_copy_assignable<directory_entry>::value,
"directory_entry's copy assignment cannot be noexcept");
const path p("foo/bar/baz");
const path p2("abc");
const directory_entry e(p);
directory_entry e2;
assert(e.path() == p && e2.path() == path());
e2 = e;
assert(e.path() == p && e2.path() == p);
directory_entry e3(p2);
e2 = e3;
assert(e2.path() == p2 && e3.path() == p2);
}
}
TEST_CASE(copy_assign_copies_cache) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym = env.create_symlink("dir/file", "sym");
{
directory_entry ent(sym);
fs::remove(sym);
directory_entry ent_cp;
ent_cp = ent;
TEST_CHECK(ent_cp.path() == sym);
TEST_CHECK(ent_cp.is_symlink());
}
{
directory_entry ent(file);
fs::remove(file);
directory_entry ent_cp;
ent_cp = ent;
TEST_CHECK(ent_cp.path() == file);
TEST_CHECK(ent_cp.is_regular_file());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry() noexcept = default;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
int main(int, char**) {
using namespace fs;
// Default
{
static_assert(std::is_nothrow_default_constructible<directory_entry>::value,
"directory_entry must have a nothrow default constructor");
directory_entry e;
assert(e.path() == path());
}
return 0;
}

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// XFAIL: apple-clang-7, clang-3.7, clang-3.8
// <filesystem>
// class directory_entry
// directory_entry() noexcept = default;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
int main(int, char**) {
using namespace fs;
// Default
{
static_assert(std::is_nothrow_default_constructible<directory_entry>::value,
"directory_entry must have a nothrow default constructor");
const directory_entry e;
assert(e.path() == path());
}
return 0;
}

View File

@ -0,0 +1,71 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry(directory_entry&&) noexcept = default;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
#include "test_convertible.hpp"
TEST_SUITE(directory_entry_path_ctor_suite)
TEST_CASE(move_ctor) {
using namespace fs;
// Move
{
static_assert(std::is_nothrow_move_constructible<directory_entry>::value,
"directory_entry must be nothrow move constructible");
const path p("foo/bar/baz");
directory_entry e(p);
assert(e.path() == p);
directory_entry e2(std::move(e));
assert(e2.path() == p);
assert(e.path() != p); // Testing moved from state.
}
}
TEST_CASE(move_ctor_copies_cache) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym = env.create_symlink("dir/file", "sym");
{
directory_entry ent(sym);
fs::remove(sym);
directory_entry ent_cp(std::move(ent));
TEST_CHECK(ent_cp.path() == sym);
TEST_CHECK(ent_cp.is_symlink());
}
{
directory_entry ent(file);
fs::remove(file);
directory_entry ent_cp(std::move(ent));
TEST_CHECK(ent_cp.path() == file);
TEST_CHECK(ent_cp.is_regular_file());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry& operator=(directory_entry const&) = default;
// directory_entry& operator=(directory_entry&&) noexcept = default;
// void assign(path const&);
// void replace_filename(path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
TEST_SUITE(directory_entry_ctor_suite)
TEST_CASE(test_move_assign_operator) {
using namespace fs;
// Copy
{
static_assert(std::is_nothrow_move_assignable<directory_entry>::value,
"directory_entry is noexcept move assignable");
const path p("foo/bar/baz");
const path p2("abc");
directory_entry e(p);
directory_entry e2(p2);
assert(e.path() == p && e2.path() == p2);
e2 = std::move(e);
assert(e2.path() == p);
assert(e.path() != p); // testing moved from state
}
}
TEST_CASE(move_assign_copies_cache) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym = env.create_symlink("dir/file", "sym");
{
directory_entry ent(sym);
fs::remove(sym);
directory_entry ent_cp;
ent_cp = std::move(ent);
TEST_CHECK(ent_cp.path() == sym);
TEST_CHECK(ent_cp.is_symlink());
}
{
directory_entry ent(file);
fs::remove(file);
directory_entry ent_cp;
ent_cp = std::move(ent);
TEST_CHECK(ent_cp.path() == file);
TEST_CHECK(ent_cp.is_regular_file());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,181 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// explicit directory_entry(const path);
// directory_entry(const path&, error_code& ec);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
#include "test_convertible.hpp"
TEST_SUITE(directory_entry_path_ctor_suite)
TEST_CASE(path_ctor) {
using namespace fs;
{
static_assert(std::is_constructible<directory_entry, const path&>::value,
"directory_entry must be constructible from path");
static_assert(
!std::is_nothrow_constructible<directory_entry, const path&>::value,
"directory_entry constructor should not be noexcept");
static_assert(!std::is_convertible<path const&, directory_entry>::value,
"directory_entry constructor should be explicit");
}
{
const path p("foo/bar/baz");
const directory_entry e(p);
TEST_CHECK(e.path() == p);
}
}
TEST_CASE(path_ec_ctor) {
using namespace fs;
{
static_assert(
std::is_constructible<directory_entry, const path&,
std::error_code&>::value,
"directory_entry must be constructible from path and error_code");
static_assert(!std::is_nothrow_constructible<directory_entry, const path&,
std::error_code&>::value,
"directory_entry constructor should not be noexcept");
static_assert(
test_convertible<directory_entry, const path&, std::error_code&>(),
"directory_entry constructor should not be explicit");
}
{
std::error_code ec = GetTestEC();
const directory_entry e(StaticEnv::File, ec);
TEST_CHECK(e.path() == StaticEnv::File);
TEST_CHECK(!ec);
}
{
const path p("foo/bar/baz");
std::error_code ec = GetTestEC();
const directory_entry e(p, ec);
TEST_CHECK(e.path() == p);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
}
}
TEST_CASE(path_ctor_calls_refresh) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym = env.create_symlink("dir/file", "sym");
{
directory_entry ent(file);
std::error_code ec = GetTestEC();
directory_entry ent_ec(file, ec);
TEST_CHECK(!ec);
LIBCPP_ONLY(remove(file));
TEST_CHECK(ent.exists());
TEST_CHECK(ent_ec.exists());
TEST_CHECK(ent.file_size() == 42);
TEST_CHECK(ent_ec.file_size() == 42);
}
env.create_file("dir/file", 101);
{
directory_entry ent(sym);
std::error_code ec = GetTestEC();
directory_entry ent_ec(sym, ec);
TEST_CHECK(!ec);
LIBCPP_ONLY(remove(file));
LIBCPP_ONLY(remove(sym));
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent_ec.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent_ec.is_regular_file());
TEST_CHECK(ent.file_size() == 101);
TEST_CHECK(ent_ec.file_size() == 101);
}
}
TEST_CASE(path_ctor_dne) {
using namespace fs;
{
std::error_code ec = GetTestEC();
directory_entry ent(StaticEnv::DNE, ec);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
TEST_CHECK(ent.path() == StaticEnv::DNE);
}
// don't report dead symlinks as an error.
{
std::error_code ec = GetTestEC();
directory_entry ent(StaticEnv::BadSymlink, ec);
TEST_CHECK(!ec);
TEST_CHECK(ent.path() == StaticEnv::BadSymlink);
}
// DNE does not cause the constructor to throw
{
directory_entry ent(StaticEnv::DNE);
TEST_CHECK(ent.path() == StaticEnv::DNE);
directory_entry ent_two(StaticEnv::BadSymlink);
TEST_CHECK(ent_two.path() == StaticEnv::BadSymlink);
}
}
TEST_CASE(path_ctor_cannot_resolve) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_out_of_dir = env.create_file("file1", 101);
const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
const path sym_in_dir = env.create_symlink("dir/file1", "dir/sym2");
permissions(dir, perms::none);
{
std::error_code ec = GetTestEC();
directory_entry ent(file, ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
TEST_CHECK(ent.path() == file);
}
{
std::error_code ec = GetTestEC();
directory_entry ent(sym_in_dir, ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
TEST_CHECK(ent.path() == sym_in_dir);
}
{
std::error_code ec = GetTestEC();
directory_entry ent(sym_out_of_dir, ec);
TEST_CHECK(!ec);
TEST_CHECK(ent.path() == sym_out_of_dir);
}
{
TEST_CHECK_NO_THROW(directory_entry(file));
TEST_CHECK_NO_THROW(directory_entry(sym_in_dir));
TEST_CHECK_NO_THROW(directory_entry(sym_out_of_dir));
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,131 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry& operator=(directory_entry const&) = default;
// directory_entry& operator=(directory_entry&&) noexcept = default;
// void assign(path const&);
// void replace_filename(path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
TEST_SUITE(directory_entry_mods_suite)
TEST_CASE(test_path_assign_method) {
using namespace fs;
const path p("foo/bar/baz");
const path p2("abc");
directory_entry e(p);
{
static_assert(std::is_same<decltype(e.assign(p)), void>::value,
"return type should be void");
static_assert(noexcept(e.assign(p)) == false,
"operation must not be noexcept");
}
{
TEST_CHECK(e.path() == p);
e.assign(p2);
TEST_CHECK(e.path() == p2 && e.path() != p);
e.assign(p);
TEST_CHECK(e.path() == p && e.path() != p2);
}
}
TEST_CASE(test_path_assign_ec_method) {
using namespace fs;
const path p("foo/bar/baz");
const path p2("abc");
{
std::error_code ec;
directory_entry e(p);
static_assert(std::is_same<decltype(e.assign(p, ec)), void>::value,
"return type should be void");
static_assert(noexcept(e.assign(p, ec)) == false,
"operation must not be noexcept");
}
{
directory_entry ent(p);
std::error_code ec = GetTestEC();
ent.assign(p2, ec);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
TEST_CHECK(ent.path() == p2);
}
}
TEST_CASE(test_assign_calls_refresh) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym = env.create_symlink("dir/file", "sym");
{
directory_entry ent;
ent.assign(file);
// removing the file demonstrates that the values where cached previously.
LIBCPP_ONLY(remove(file));
TEST_CHECK(ent.is_regular_file());
}
env.create_file("dir/file", 101);
{
directory_entry ent;
ent.assign(sym);
LIBCPP_ONLY(remove(file));
LIBCPP_ONLY(remove(sym));
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
}
}
TEST_CASE(test_assign_propagates_error) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
const path file_out_of_dir = env.create_file("file1");
const path sym_in_dir = env.create_symlink("file1", "dir/sym1");
permissions(dir, perms::none);
{
directory_entry ent;
std::error_code ec = GetTestEC();
ent.assign(file, ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
}
{
directory_entry ent;
std::error_code ec = GetTestEC();
ent.assign(sym_in_dir, ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
}
{
directory_entry ent;
std::error_code ec = GetTestEC();
ent.assign(sym_out_of_dir, ec);
TEST_CHECK(!ec);
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,340 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry& operator=(directory_entry const&) = default;
// directory_entry& operator=(directory_entry&&) noexcept = default;
// void assign(path const&);
// void replace_filename(path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
TEST_SUITE(directory_entry_mods_suite)
TEST_CASE(test_refresh_method) {
using namespace fs;
{
directory_entry e;
static_assert(noexcept(e.refresh()) == false,
"operation cannot be noexcept");
static_assert(std::is_same<decltype(e.refresh()), void>::value,
"operation must return void");
}
{
directory_entry e;
e.refresh();
TEST_CHECK(!e.exists());
}
}
TEST_CASE(test_refresh_ec_method) {
using namespace fs;
{
directory_entry e;
std::error_code ec;
static_assert(noexcept(e.refresh(ec)), "operation should be noexcept");
static_assert(std::is_same<decltype(e.refresh(ec)), void>::value,
"operation must return void");
}
{
directory_entry e;
std::error_code ec = GetTestEC();
e.refresh(ec);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
}
}
TEST_CASE(refresh_on_file_dne) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const perms old_perms = status(dir).permissions();
// test file doesn't exist
{
directory_entry ent(file);
remove(file);
TEST_CHECK(ent.exists());
ent.refresh();
permissions(dir, perms::none);
TEST_CHECK(!ent.exists());
}
permissions(dir, old_perms);
env.create_file("dir/file", 101);
{
directory_entry ent(file);
remove(file);
TEST_CHECK(ent.exists());
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
permissions(dir, perms::none);
TEST_CHECK(!ent.exists());
}
}
void remove_if_exists(const fs::path& p) {
std::error_code ec;
remove(p, ec);
}
TEST_CASE(refresh_on_bad_symlink) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path sym = env.create_symlink("dir/file", "sym");
const perms old_perms = status(dir).permissions();
// test file doesn't exist
{
directory_entry ent(sym);
LIBCPP_ONLY(remove(file));
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent.exists());
remove_if_exists(file);
ent.refresh();
LIBCPP_ONLY(permissions(dir, perms::none));
TEST_CHECK(ent.is_symlink());
TEST_CHECK(!ent.is_regular_file());
TEST_CHECK(!ent.exists());
}
permissions(dir, old_perms);
env.create_file("dir/file", 101);
{
directory_entry ent(sym);
LIBCPP_ONLY(remove(file));
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent.exists());
remove_if_exists(file);
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(!ec); // we don't report bad symlinks as an error.
LIBCPP_ONLY(permissions(dir, perms::none));
TEST_CHECK(!ent.exists());
}
}
TEST_CASE(refresh_cannot_resolve) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_out_of_dir = env.create_file("file1", 99);
const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
const path sym_in_dir = env.create_symlink("file1", "dir/sym1");
perms old_perms = status(dir).permissions();
{
directory_entry ent(file);
permissions(dir, perms::none);
TEST_CHECK(ent.is_regular_file());
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
TEST_CHECK(ent.path() == file);
ExceptionChecker Checker(file, std::errc::permission_denied,
"directory_entry::refresh");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh());
}
permissions(dir, old_perms);
{
directory_entry ent(sym_in_dir);
permissions(dir, perms::none);
TEST_CHECK(ent.is_symlink());
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
TEST_CHECK(ent.path() == sym_in_dir);
ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied,
"directory_entry::refresh");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh());
}
permissions(dir, old_perms);
{
directory_entry ent(sym_out_of_dir);
permissions(dir, perms::none);
TEST_CHECK(ent.is_symlink());
// Failure to resolve the linked entity due to permissions is not
// reported as an error.
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(!ec);
TEST_CHECK(ent.is_symlink());
ec = GetTestEC();
TEST_CHECK(ent.exists(ec) == false);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
TEST_CHECK(ent.path() == sym_out_of_dir);
}
permissions(dir, old_perms);
{
directory_entry ent_file(file);
directory_entry ent_sym(sym_in_dir);
directory_entry ent_sym2(sym_out_of_dir);
permissions(dir, perms::none);
((void)ent_file);
((void)ent_sym);
TEST_CHECK_THROW(filesystem_error, ent_file.refresh());
TEST_CHECK_THROW(filesystem_error, ent_sym.refresh());
TEST_CHECK_NO_THROW(ent_sym2);
}
}
TEST_CASE(refresh_doesnt_throw_on_dne_but_reports_it) {
using namespace fs;
scoped_test_env env;
const path file = env.create_file("file1", 42);
const path sym = env.create_symlink("file1", "sym");
{
directory_entry ent(file);
TEST_CHECK(ent.file_size() == 42);
remove(file);
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
TEST_CHECK_NO_THROW(ent.refresh());
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
// doesn't throw!
TEST_CHECK_THROW(filesystem_error, ent.file_size());
}
env.create_file("file1", 99);
{
directory_entry ent(sym);
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent.file_size() == 99);
remove(file);
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(!ec);
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
TEST_CHECK_THROW(filesystem_error, ent.file_size());
}
}
TEST_CASE(access_cache_after_refresh_fails) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_out_of_dir = env.create_file("file1", 101);
const path sym = env.create_symlink("dir/file", "sym");
const path sym_in_dir = env.create_symlink("dir/file", "dir/sym2");
const perms old_perms = status(dir).permissions();
#define CHECK_ACCESS(func, expect) \
ec = GetTestEC(); \
TEST_CHECK(ent.func(ec) == expect); \
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied))
// test file doesn't exist
{
directory_entry ent(file);
TEST_CHECK(!ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent.exists());
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
CHECK_ACCESS(exists, false);
CHECK_ACCESS(is_symlink, false);
CHECK_ACCESS(last_write_time, file_time_type::min());
CHECK_ACCESS(hard_link_count, uintmax_t(-1));
}
permissions(dir, old_perms);
{
directory_entry ent(sym_in_dir);
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent.exists());
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
CHECK_ACCESS(exists, false);
CHECK_ACCESS(is_symlink, false);
CHECK_ACCESS(last_write_time, file_time_type::min());
CHECK_ACCESS(hard_link_count, uintmax_t(-1));
}
permissions(dir, old_perms);
{
directory_entry ent(sym);
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent.exists());
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.refresh(ec);
TEST_CHECK(!ec);
TEST_CHECK(ent.is_symlink());
CHECK_ACCESS(exists, false);
CHECK_ACCESS(is_regular_file, false);
CHECK_ACCESS(last_write_time, file_time_type::min());
CHECK_ACCESS(hard_link_count, uintmax_t(-1));
}
#undef CHECK_ACCESS
}
TEST_SUITE_END()

View File

@ -0,0 +1,168 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// directory_entry& operator=(directory_entry const&) = default;
// directory_entry& operator=(directory_entry&&) noexcept = default;
// void assign(path const&);
// void replace_filename(path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
TEST_SUITE(directory_entry_mods_suite)
TEST_CASE(test_replace_filename_method) {
using namespace fs;
{
directory_entry e;
path replace;
static_assert(noexcept(e.replace_filename(replace)) == false,
"operation cannot be noexcept");
static_assert(
std::is_same<decltype(e.replace_filename(replace)), void>::value,
"operation must return void");
}
{
const path p("/path/to/foo.exe");
const path replace("bar.out");
const path expect("/path/to/bar.out");
directory_entry e(p);
TEST_CHECK(e.path() == p);
e.replace_filename(replace);
TEST_CHECK(e.path() == expect);
}
}
TEST_CASE(test_replace_filename_ec_method) {
using namespace fs;
{
directory_entry e;
path replace;
std::error_code ec;
static_assert(noexcept(e.replace_filename(replace, ec)) == false,
"operation cannot be noexcept");
static_assert(
std::is_same<decltype(e.replace_filename(replace, ec)), void>::value,
"operation must return void");
}
{
const path p("/path/to/foo.exe");
const path replace("bar.out");
const path expect("/path/to/bar.out");
directory_entry e(p);
TEST_CHECK(e.path() == p);
std::error_code ec = GetTestEC();
e.replace_filename(replace, ec);
TEST_CHECK(e.path() == expect);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
}
{
const path p = StaticEnv::EmptyFile;
const path expect = StaticEnv::NonEmptyFile;
const path replace = StaticEnv::NonEmptyFile.filename();
TEST_REQUIRE(expect.parent_path() == p.parent_path());
directory_entry e(p);
TEST_CHECK(e.path() == p);
std::error_code ec = GetTestEC();
e.replace_filename(replace, ec);
TEST_CHECK(e.path() == expect);
TEST_CHECK(!ec);
}
}
TEST_CASE(test_replace_filename_calls_refresh) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_two = env.create_file("dir/file_two", 101);
const path sym = env.create_symlink("dir/file", "sym");
const path sym_two = env.create_symlink("dir/file_two", "sym_two");
{
directory_entry ent(file);
ent.replace_filename(file_two.filename());
TEST_REQUIRE(ent.path() == file_two);
// removing the file demonstrates that the values where cached previously.
LIBCPP_ONLY(remove(file_two));
TEST_CHECK(ent.file_size() == 101);
}
env.create_file("dir/file_two", 99);
{
directory_entry ent(sym);
ent.replace_filename(sym_two.filename());
TEST_REQUIRE(ent.path() == sym_two);
LIBCPP_ONLY(remove(file_two));
LIBCPP_ONLY(remove(sym_two));
TEST_CHECK(ent.is_symlink());
TEST_CHECK(ent.is_regular_file());
TEST_CHECK(ent.file_size() == 99);
}
}
TEST_CASE(test_replace_filename_propagates_error) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_two = env.create_file("dir/file_two", 99);
const path file_out_of_dir = env.create_file("file_three", 101);
const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
const path sym_out_of_dir_two = env.create_symlink("dir/file", "sym_two");
const path sym_in_dir = env.create_symlink("file_two", "dir/sym_three");
const path sym_in_dir_two = env.create_symlink("file_two", "dir/sym_four");
const perms old_perms = status(dir).permissions();
{
directory_entry ent(file);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.replace_filename(file_two.filename(), ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
}
permissions(dir, old_perms);
{
directory_entry ent(sym_in_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.replace_filename(sym_in_dir_two.filename(), ec);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
}
permissions(dir, old_perms);
{
directory_entry ent(sym_out_of_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.replace_filename(sym_out_of_dir_two.filename(), ec);
TEST_CHECK(!ec);
TEST_CHECK(ent.is_symlink());
ec = GetTestEC();
TEST_CHECK(!ent.exists(ec));
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,82 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// bool operator==(directory_entry const&) const noexcept;
// bool operator!=(directory_entry const&) const noexcept;
// bool operator< (directory_entry const&) const noexcept;
// bool operator<=(directory_entry const&) const noexcept;
// bool operator> (directory_entry const&) const noexcept;
// bool operator>=(directory_entry const&) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#define CHECK_OP(Op) \
static_assert(std::is_same<decltype(ce. operator Op (ce)), bool>::value, ""); \
static_assert(noexcept(ce.operator Op (ce)), "Operation must be noexcept" )
void test_comparison_signatures() {
using namespace fs;
path const p("foo/bar/baz");
// Check that the operators are member functions with the correct signatures.
{
directory_entry const ce(p);
CHECK_OP(==);
CHECK_OP(!=);
CHECK_OP(< );
CHECK_OP(<=);
CHECK_OP(> );
CHECK_OP(>=);
}
}
#undef CHECK_OP
// The actual semantics of the comparisons are testing via paths operators.
void test_comparisons_simple() {
using namespace fs;
typedef std::pair<path, path> TestType;
TestType TestCases[] =
{
{"", ""},
{"", "a"},
{"a", "a"},
{"a", "b"},
{"foo/bar/baz", "foo/bar/baz/"}
};
auto TestFn = [](path const& LHS, const directory_entry& LHSE,
path const& RHS, const directory_entry& RHSE) {
assert((LHS == RHS) == (LHSE == RHSE));
assert((LHS != RHS) == (LHSE != RHSE));
assert((LHS < RHS) == (LHSE < RHSE));
assert((LHS <= RHS) == (LHSE <= RHSE));
assert((LHS > RHS) == (LHSE > RHSE));
assert((LHS >= RHS) == (LHSE >= RHSE));
};
for (auto const& TC : TestCases) {
const directory_entry L(TC.first);
const directory_entry R(TC.second);
TestFn(TC.first, L, TC.second, R);
TestFn(TC.second, R, TC.first, L);
}
}
int main(int, char**) {
test_comparison_signatures();
test_comparisons_simple();
return 0;
}

View File

@ -0,0 +1,241 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// uintmax_t file_size() const;
// uintmax_t file_size(error_code const&) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "filesystem_test_helper.hpp"
#include "rapid-cxx-test.hpp"
#include <iostream>
TEST_SUITE(directory_entry_obs_testsuite)
TEST_CASE(signatures) {
using namespace fs;
{
const fs::directory_entry e = {};
std::error_code ec;
static_assert(std::is_same<decltype(e.file_size()), uintmax_t>::value, "");
static_assert(std::is_same<decltype(e.file_size(ec)), uintmax_t>::value,
"");
static_assert(noexcept(e.file_size()) == false, "");
static_assert(noexcept(e.file_size(ec)) == true, "");
}
}
TEST_CASE(basic) {
using namespace fs;
scoped_test_env env;
const path file = env.create_file("file", 42);
const path dir = env.create_dir("dir");
const path sym = env.create_symlink("file", "sym");
{
directory_entry ent(file);
uintmax_t expect = file_size(ent);
TEST_CHECK(expect == 42);
// Remove the file to show that the results were already in the cache.
LIBCPP_ONLY(remove(file));
std::error_code ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == expect);
TEST_CHECK(!ec);
}
env.create_file("file", 99);
{
directory_entry ent(sym);
uintmax_t expect = file_size(ent);
TEST_CHECK(expect == 99);
LIBCPP_ONLY(remove(ent));
std::error_code ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == 99);
TEST_CHECK(!ec);
}
}
TEST_CASE(not_regular_file) {
using namespace fs;
scoped_test_env env;
struct {
const path p;
std::errc expected_err;
} TestCases[] = {
{env.create_dir("dir"), std::errc::is_a_directory},
{env.create_fifo("fifo"), std::errc::not_supported},
{env.create_symlink("dir", "sym"), std::errc::is_a_directory}};
for (auto const& TC : TestCases) {
const path& p = TC.p;
directory_entry ent(p);
TEST_CHECK(ent.path() == p);
std::error_code ec = GetTestEC(0);
std::error_code other_ec = GetTestEC(1);
uintmax_t expect = file_size(p, other_ec);
uintmax_t got = ent.file_size(ec);
TEST_CHECK(got == expect);
TEST_CHECK(got == uintmax_t(-1));
TEST_CHECK(ec == other_ec);
TEST_CHECK(ErrorIs(ec, TC.expected_err));
ExceptionChecker Checker(p, TC.expected_err, "directory_entry::file_size");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size());
}
}
TEST_CASE(error_reporting) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_out_of_dir = env.create_file("file2", 101);
const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
const path sym_in_dir = env.create_symlink("file2", "dir/sym2");
const perms old_perms = status(dir).permissions();
// test a file which doesn't exist
{
directory_entry ent;
std::error_code ec = GetTestEC();
ent.assign(StaticEnv::DNE, ec);
TEST_REQUIRE(ent.path() == StaticEnv::DNE);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ExceptionChecker Checker(StaticEnv::DNE,
std::errc::no_such_file_or_directory,
"directory_entry::file_size");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size());
}
// test a dead symlink
{
directory_entry ent;
std::error_code ec = GetTestEC();
uintmax_t expect_bad = file_size(StaticEnv::BadSymlink, ec);
TEST_CHECK(expect_bad == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ec = GetTestEC();
ent.assign(StaticEnv::BadSymlink, ec);
TEST_REQUIRE(ent.path() == StaticEnv::BadSymlink);
TEST_CHECK(!ec);
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == expect_bad);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ExceptionChecker Checker(StaticEnv::BadSymlink,
std::errc::no_such_file_or_directory,
"directory_entry::file_size");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size());
}
// test a file w/o appropriate permissions.
{
directory_entry ent;
uintmax_t expect_good = file_size(file);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(file, ec);
TEST_REQUIRE(ent.path() == file);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(file, std::errc::permission_denied, "file_size");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.file_size());
}
permissions(dir, old_perms);
// test a symlink w/o appropriate permissions.
{
directory_entry ent;
uintmax_t expect_good = file_size(sym_in_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(sym_in_dir, ec);
TEST_REQUIRE(ent.path() == sym_in_dir);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied,
"file_size");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.file_size());
}
permissions(dir, old_perms);
// test a symlink to a file w/o appropriate permissions
{
directory_entry ent;
uintmax_t expect_good = file_size(sym_out_of_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(sym_out_of_dir, ec);
TEST_REQUIRE(ent.path() == sym_out_of_dir);
TEST_CHECK(!ec);
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(sym_out_of_dir, std::errc::permission_denied,
"file_size");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.file_size(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.file_size());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,257 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// file_status status() const;
// file_status status(error_code const&) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "filesystem_test_helper.hpp"
#include "rapid-cxx-test.hpp"
TEST_SUITE(directory_entry_obs_testsuite)
TEST_CASE(file_dne) {
using namespace fs;
directory_entry p("dne");
}
TEST_CASE(signatures) {
using namespace fs;
const directory_entry e = {};
std::error_code ec;
#define TEST_FUNC(name) \
static_assert(std::is_same<decltype(e.name()), bool>::value, \
"wrong return type"); \
static_assert(noexcept(e.name()) == false, "should not be noexcept"); \
static_assert(std::is_same<decltype(e.name(ec)), bool>::value, \
"wrong return type"); \
static_assert(noexcept(e.name(ec)) == true, "should be noexcept")
TEST_FUNC(exists);
TEST_FUNC(is_block_file);
TEST_FUNC(is_character_file);
TEST_FUNC(is_directory);
TEST_FUNC(is_fifo);
TEST_FUNC(is_other);
TEST_FUNC(is_regular_file);
TEST_FUNC(is_socket);
TEST_FUNC(is_symlink);
#undef TEST_FUNC
}
TEST_CASE(test_without_ec) {
using namespace fs;
using fs::directory_entry;
using fs::file_status;
using fs::path;
scoped_test_env env;
path f = env.create_file("foo", 42);
path d = env.create_dir("dir");
path fifo = env.create_fifo("fifo");
path hl = env.create_hardlink("foo", "hl");
for (auto p : {hl, f, d, fifo}) {
directory_entry e(p);
file_status st = status(p);
file_status sym_st = symlink_status(p);
fs::remove(p);
TEST_REQUIRE(e.exists());
TEST_REQUIRE(!exists(p));
TEST_CHECK(e.exists() == exists(st));
TEST_CHECK(e.is_block_file() == is_block_file(st));
TEST_CHECK(e.is_character_file() == is_character_file(st));
TEST_CHECK(e.is_directory() == is_directory(st));
TEST_CHECK(e.is_fifo() == is_fifo(st));
TEST_CHECK(e.is_other() == is_other(st));
TEST_CHECK(e.is_regular_file() == is_regular_file(st));
TEST_CHECK(e.is_socket() == is_socket(st));
TEST_CHECK(e.is_symlink() == is_symlink(sym_st));
}
}
TEST_CASE(test_with_ec) {
using namespace fs;
using fs::directory_entry;
using fs::file_status;
using fs::path;
scoped_test_env env;
path f = env.create_file("foo", 42);
path d = env.create_dir("dir");
path fifo = env.create_fifo("fifo");
path hl = env.create_hardlink("foo", "hl");
for (auto p : {hl, f, d, fifo}) {
directory_entry e(p);
std::error_code status_ec = GetTestEC();
std::error_code sym_status_ec = GetTestEC(1);
file_status st = status(p, status_ec);
file_status sym_st = symlink_status(p, sym_status_ec);
fs::remove(p);
std::error_code ec = GetTestEC(2);
auto CheckEC = [&](std::error_code const& other_ec) {
bool res = ec == other_ec;
ec = GetTestEC(2);
return res;
};
TEST_REQUIRE(e.exists(ec));
TEST_CHECK(CheckEC(status_ec));
TEST_REQUIRE(!exists(p));
TEST_CHECK(e.exists(ec) == exists(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_block_file(ec) == is_block_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_character_file(ec) == is_character_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_directory(ec) == is_directory(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_fifo(ec) == is_fifo(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_other(ec) == is_other(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_regular_file(ec) == is_regular_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_socket(ec) == is_socket(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_symlink(ec) == is_symlink(sym_st));
TEST_CHECK(CheckEC(sym_status_ec));
}
}
TEST_CASE(test_with_ec_dne) {
using namespace fs;
using fs::directory_entry;
using fs::file_status;
using fs::path;
for (auto p : {StaticEnv::DNE, StaticEnv::BadSymlink}) {
directory_entry e(p);
std::error_code status_ec = GetTestEC();
std::error_code sym_status_ec = GetTestEC(1);
file_status st = status(p, status_ec);
file_status sym_st = symlink_status(p, sym_status_ec);
std::error_code ec = GetTestEC(2);
auto CheckEC = [&](std::error_code const& other_ec) {
bool res = ec == other_ec;
ec = GetTestEC(2);
return res;
};
TEST_CHECK(e.exists(ec) == exists(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_block_file(ec) == is_block_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_character_file(ec) == is_character_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_directory(ec) == is_directory(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_fifo(ec) == is_fifo(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_other(ec) == is_other(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_regular_file(ec) == is_regular_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_socket(ec) == is_socket(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_symlink(ec) == is_symlink(sym_st));
TEST_CHECK(CheckEC(sym_status_ec));
}
}
TEST_CASE(test_with_ec_cannot_resolve) {
using namespace fs;
using fs::directory_entry;
using fs::file_status;
using fs::path;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_out_of_dir = env.create_file("file2", 99);
const path sym = env.create_symlink("file2", "dir/sym");
perms old_perms = fs::status(dir).permissions();
for (auto p : {file, sym}) {
permissions(dir, old_perms);
directory_entry e(p);
permissions(dir, perms::none);
std::error_code dummy_ec;
e.refresh(dummy_ec);
TEST_REQUIRE(dummy_ec);
std::error_code status_ec = GetTestEC();
std::error_code sym_status_ec = GetTestEC(1);
file_status st = status(p, status_ec);
file_status sym_st = symlink_status(p, sym_status_ec);
std::error_code ec = GetTestEC(2);
auto CheckEC = [&](std::error_code const& other_ec) {
bool res = ec == other_ec;
ec = GetTestEC(2);
return res;
};
TEST_CHECK(e.exists(ec) == exists(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_block_file(ec) == is_block_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_character_file(ec) == is_character_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_directory(ec) == is_directory(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_fifo(ec) == is_fifo(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_other(ec) == is_other(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_regular_file(ec) == is_regular_file(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_socket(ec) == is_socket(st));
TEST_CHECK(CheckEC(status_ec));
TEST_CHECK(e.is_symlink(ec) == is_symlink(sym_st));
TEST_CHECK(CheckEC(sym_status_ec));
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,241 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// uintmax_t hard_link_count() const;
// uintmax_t hard_link_count(error_code const&) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "filesystem_test_helper.hpp"
#include "rapid-cxx-test.hpp"
TEST_SUITE(directory_entry_obs_testsuite)
TEST_CASE(signatures) {
using namespace fs;
{
const directory_entry e = {};
std::error_code ec;
static_assert(std::is_same<decltype(e.hard_link_count()), uintmax_t>::value, "");
static_assert(std::is_same<decltype(e.hard_link_count(ec)), uintmax_t>::value,
"");
static_assert(noexcept(e.hard_link_count()) == false, "");
static_assert(noexcept(e.hard_link_count(ec)) == true, "");
}
}
TEST_CASE(basic) {
using namespace fs;
scoped_test_env env;
const path file = env.create_file("file", 42);
const path dir = env.create_dir("dir");
const path sym = env.create_symlink("file", "sym");
{
directory_entry ent(file);
uintmax_t expect = hard_link_count(ent);
// Remove the file to show that the results were already in the cache.
LIBCPP_ONLY(remove(file));
std::error_code ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == expect);
TEST_CHECK(!ec);
}
{
directory_entry ent(dir);
uintmax_t expect = hard_link_count(ent);
LIBCPP_ONLY(remove(dir));
std::error_code ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == expect);
TEST_CHECK(!ec);
}
env.create_file("file", 99);
env.create_hardlink("file", "hl");
{
directory_entry ent(sym);
std::error_code ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == 2);
TEST_CHECK(!ec);
}
}
TEST_CASE(not_regular_file) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path dir2 = env.create_dir("dir/dir2");
const path fifo = env.create_fifo("dir/fifo");
const path sym_to_fifo = env.create_symlink("dir/fifo", "dir/sym");
const perms old_perms = status(dir).permissions();
for (auto p : {dir2, fifo, sym_to_fifo}) {
permissions(dir, old_perms);
std::error_code dummy_ec = GetTestEC();
directory_entry ent(p, dummy_ec);
TEST_CHECK(!dummy_ec);
uintmax_t expect = hard_link_count(p);
LIBCPP_ONLY(permissions(dir, perms::none));
std::error_code ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == expect);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.hard_link_count());
}
}
TEST_CASE(error_reporting) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_out_of_dir = env.create_file("file2", 101);
const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
const path sym_in_dir = env.create_symlink("file2", "dir/sym2");
const perms old_perms = status(dir).permissions();
// test a file which doesn't exist
{
directory_entry ent;
std::error_code ec = GetTestEC();
ent.assign(StaticEnv::DNE, ec);
TEST_CHECK(ec);
TEST_REQUIRE(ent.path() == StaticEnv::DNE);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ExceptionChecker Checker(StaticEnv::DNE,
std::errc::no_such_file_or_directory,
"directory_entry::hard_link_count");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count());
}
// test a dead symlink
{
directory_entry ent;
std::error_code ec = GetTestEC();
uintmax_t expect_bad = hard_link_count(StaticEnv::BadSymlink, ec);
TEST_CHECK(expect_bad == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ec = GetTestEC();
ent.assign(StaticEnv::BadSymlink, ec);
TEST_REQUIRE(ent.path() == StaticEnv::BadSymlink);
TEST_CHECK(!ec);
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == expect_bad);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ExceptionChecker Checker(StaticEnv::BadSymlink,
std::errc::no_such_file_or_directory,
"directory_entry::hard_link_count");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count());
}
// test a file w/o appropriate permissions.
{
directory_entry ent;
uintmax_t expect_good = hard_link_count(file);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(file, ec);
TEST_REQUIRE(ent.path() == file);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(file, std::errc::permission_denied,
"hard_link_count");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.hard_link_count());
}
permissions(dir, old_perms);
// test a symlink w/o appropriate permissions.
{
directory_entry ent;
uintmax_t expect_good = hard_link_count(sym_in_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(sym_in_dir, ec);
TEST_REQUIRE(ent.path() == sym_in_dir);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied,
"hard_link_count");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.hard_link_count());
}
permissions(dir, old_perms);
// test a symlink to a file w/o appropriate permissions
{
directory_entry ent;
uintmax_t expect_good = hard_link_count(sym_out_of_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(sym_out_of_dir, ec);
TEST_REQUIRE(ent.path() == sym_out_of_dir);
TEST_CHECK(!ec);
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1));
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(sym_out_of_dir, std::errc::permission_denied,
"hard_link_count");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.hard_link_count(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.hard_link_count());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,214 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// file_time_type last_write_time() const;
// file_time_type last_write_time(error_code const&) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "filesystem_test_helper.hpp"
#include "rapid-cxx-test.hpp"
TEST_SUITE(directory_entry_obs_testsuite)
TEST_CASE(signatures) {
using namespace fs;
{
const fs::directory_entry e = {};
std::error_code ec;
static_assert(std::is_same<decltype(e.last_write_time()), file_time_type>::value,
"");
static_assert(std::is_same<decltype(e.last_write_time(ec)), file_time_type>::value,
"");
static_assert(noexcept(e.last_write_time()) == false, "");
static_assert(noexcept(e.last_write_time(ec)) == true, "");
}
}
TEST_CASE(basic) {
using namespace fs;
scoped_test_env env;
const path file = env.create_file("file", 42);
const path dir = env.create_dir("dir");
const path sym = env.create_symlink("file", "sym");
{
directory_entry ent(file);
file_time_type expect = last_write_time(ent);
// Remove the file to show that the results were already in the cache.
LIBCPP_ONLY(remove(file));
std::error_code ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == expect);
TEST_CHECK(!ec);
}
{
directory_entry ent(dir);
file_time_type expect = last_write_time(ent);
LIBCPP_ONLY(remove(dir));
std::error_code ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == expect);
TEST_CHECK(!ec);
}
env.create_file("file", 99);
{
directory_entry ent(sym);
file_time_type expect = last_write_time(sym);
std::error_code ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == expect);
TEST_CHECK(!ec);
}
}
TEST_CASE(error_reporting) {
using namespace fs;
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path file_out_of_dir = env.create_file("file2", 101);
const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
const path sym_in_dir = env.create_symlink("file2", "dir/sym2");
const perms old_perms = status(dir).permissions();
// test a file which doesn't exist
{
directory_entry ent;
std::error_code ec = GetTestEC();
ent.assign(StaticEnv::DNE, ec);
TEST_REQUIRE(ent.path() == StaticEnv::DNE);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == file_time_type::min());
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ExceptionChecker Checker(StaticEnv::DNE,
std::errc::no_such_file_or_directory,
"directory_entry::last_write_time");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time());
}
// test a dead symlink
{
directory_entry ent;
std::error_code ec = GetTestEC();
file_time_type expect_bad = last_write_time(StaticEnv::BadSymlink, ec);
TEST_CHECK(expect_bad == file_time_type::min());
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ec = GetTestEC();
ent.assign(StaticEnv::BadSymlink, ec);
TEST_REQUIRE(ent.path() == StaticEnv::BadSymlink);
TEST_CHECK(!ec);
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == expect_bad);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
ExceptionChecker Checker(StaticEnv::BadSymlink,
std::errc::no_such_file_or_directory,
"directory_entry::last_write_time");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time());
}
// test a file w/o appropriate permissions.
{
directory_entry ent;
file_time_type expect_good = last_write_time(file);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(file, ec);
TEST_REQUIRE(ent.path() == file);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == file_time_type::min());
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(file, std::errc::permission_denied,
"last_write_time");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.last_write_time());
}
permissions(dir, old_perms);
// test a symlink w/o appropriate permissions.
{
directory_entry ent;
file_time_type expect_good = last_write_time(sym_in_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(sym_in_dir, ec);
TEST_REQUIRE(ent.path() == sym_in_dir);
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == file_time_type::min());
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied,
"last_write_time");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.last_write_time());
}
permissions(dir, old_perms);
// test a symlink to a file w/o appropriate permissions
{
directory_entry ent;
file_time_type expect_good = last_write_time(sym_out_of_dir);
permissions(dir, perms::none);
std::error_code ec = GetTestEC();
ent.assign(sym_out_of_dir, ec);
TEST_REQUIRE(ent.path() == sym_out_of_dir);
TEST_CHECK(!ec);
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == file_time_type::min());
TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
ExceptionChecker Checker(sym_out_of_dir, std::errc::permission_denied,
"last_write_time");
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time());
permissions(dir, old_perms);
ec = GetTestEC();
TEST_CHECK(ent.last_write_time(ec) == expect_good);
TEST_CHECK(!ec);
TEST_CHECK_NO_THROW(ent.last_write_time());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,89 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// const path& path() const noexcept;
// operator const path&() const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
void test_path_method() {
using namespace fs;
const path p("foo/bar/baz.exe");
const path p2("abc");
{
directory_entry nce;
const directory_entry e("");
static_assert(std::is_same<decltype(e.path()), const path&>::value, "");
static_assert(std::is_same<decltype(nce.path()), const path&>::value, "");
static_assert(noexcept(e.path()) && noexcept(nce.path()), "");
}
{
directory_entry e(p);
path const& pref = e.path();
assert(pref == p);
assert(&pref == &e.path());
e.assign(p2);
assert(pref == p2);
assert(&pref == &e.path());
}
}
void test_path_conversion() {
using namespace fs;
const path p("foo/bar/baz.exe");
const path p2("abc");
{
directory_entry nce;
const directory_entry e("");
// Check conversions exist
static_assert(std::is_convertible<directory_entry&, path const&>::value, "");
static_assert(std::is_convertible<directory_entry const&, path const&>::value, "");
static_assert(std::is_convertible<directory_entry &&, path const&>::value, "");
static_assert(std::is_convertible<directory_entry const&&, path const&>::value, "");
// Not convertible to non-const
static_assert(!std::is_convertible<directory_entry&, path&>::value, "");
static_assert(!std::is_convertible<directory_entry const&, path&>::value, "");
static_assert(!std::is_convertible<directory_entry &&, path&>::value, "");
static_assert(!std::is_convertible<directory_entry const&&, path&>::value, "");
// conversions are noexcept
static_assert(noexcept(e.operator fs::path const&()) &&
noexcept(e.operator fs::path const&()), "");
}
// const
{
directory_entry const e(p);
path const& pref = e;
assert(&pref == &e.path());
}
// non-const
{
directory_entry e(p);
path const& pref = e;
assert(&pref == &e.path());
e.assign(p2);
assert(pref == p2);
assert(&pref == &e.path());
}
}
int main(int, char**) {
test_path_method();
test_path_conversion();
return 0;
}

View File

@ -0,0 +1,57 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// file_status status() const;
// file_status status(error_code const&) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "filesystem_test_helper.hpp"
#include "rapid-cxx-test.hpp"
TEST_SUITE(directory_entry_status_testsuite)
TEST_CASE(test_basic) {
using namespace fs;
{
const fs::directory_entry e("foo");
std::error_code ec;
static_assert(std::is_same<decltype(e.status()), fs::file_status>::value, "");
static_assert(std::is_same<decltype(e.status(ec)), fs::file_status>::value, "");
static_assert(noexcept(e.status()) == false, "");
static_assert(noexcept(e.status(ec)) == true, "");
}
path TestCases[] = {StaticEnv::File, StaticEnv::Dir, StaticEnv::SymlinkToFile,
StaticEnv::DNE};
for (const auto& p : TestCases) {
const directory_entry e(p);
std::error_code pec = GetTestEC(), eec = GetTestEC(1);
file_status ps = fs::status(p, pec);
file_status es = e.status(eec);
TEST_CHECK(ps.type() == es.type());
TEST_CHECK(ps.permissions() == es.permissions());
TEST_CHECK(pec == eec);
}
for (const auto& p : TestCases) {
const directory_entry e(p);
file_status ps = fs::status(p);
file_status es = e.status();
TEST_CHECK(ps.type() == es.type());
TEST_CHECK(ps.permissions() == es.permissions());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,57 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_entry
// file_status symlink_status() const;
// file_status symlink_status(error_code&) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "filesystem_test_helper.hpp"
#include "rapid-cxx-test.hpp"
TEST_SUITE(directory_entry_obs_suite)
TEST_CASE(test_signature) {
using namespace fs;
{
const directory_entry e("foo");
std::error_code ec;
static_assert(std::is_same<decltype(e.symlink_status()), file_status>::value, "");
static_assert(std::is_same<decltype(e.symlink_status(ec)), file_status>::value, "");
static_assert(noexcept(e.symlink_status()) == false, "");
static_assert(noexcept(e.symlink_status(ec)) == true, "");
}
path TestCases[] = {StaticEnv::File, StaticEnv::Dir, StaticEnv::SymlinkToFile,
StaticEnv::DNE};
for (const auto& p : TestCases) {
const directory_entry e(p);
std::error_code pec = GetTestEC(), eec = GetTestEC(1);
file_status ps = fs::symlink_status(p, pec);
file_status es = e.symlink_status(eec);
TEST_CHECK(ps.type() == es.type());
TEST_CHECK(ps.permissions() == es.permissions());
TEST_CHECK(pec == eec);
}
for (const auto& p : TestCases) {
const directory_entry e(p);
file_status ps = fs::symlink_status(p);
file_status es = e.symlink_status();
TEST_CHECK(ps.type() == es.type());
TEST_CHECK(ps.permissions() == es.permissions());
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// directory_iterator(directory_iterator const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(directory_iterator_copy_construct_tests)
TEST_CASE(test_constructor_signature)
{
using D = directory_iterator;
static_assert(std::is_copy_constructible<D>::value, "");
}
TEST_CASE(test_copy_end_iterator)
{
const directory_iterator endIt;
directory_iterator it(endIt);
TEST_CHECK(it == endIt);
}
TEST_CASE(test_copy_valid_iterator)
{
const path testDir = StaticEnv::Dir;
const directory_iterator endIt{};
const directory_iterator it(testDir);
TEST_REQUIRE(it != endIt);
const path entry = *it;
const directory_iterator it2(it);
TEST_REQUIRE(it2 == it);
TEST_CHECK(*it2 == entry);
TEST_CHECK(*it == entry);
}
TEST_SUITE_END()

View File

@ -0,0 +1,97 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// directory_iterator& operator=(directory_iterator const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(directory_iterator_copy_assign_tests)
TEST_CASE(test_assignment_signature)
{
using D = directory_iterator;
static_assert(std::is_copy_assignable<D>::value, "");
}
TEST_CASE(test_copy_to_end_iterator)
{
const path testDir = StaticEnv::Dir;
const directory_iterator from(testDir);
TEST_REQUIRE(from != directory_iterator{});
const path entry = *from;
directory_iterator to{};
to = from;
TEST_REQUIRE(to == from);
TEST_CHECK(*to == entry);
TEST_CHECK(*from == entry);
}
TEST_CASE(test_copy_from_end_iterator)
{
const path testDir = StaticEnv::Dir;
const directory_iterator from{};
directory_iterator to(testDir);
TEST_REQUIRE(to != directory_iterator{});
to = from;
TEST_REQUIRE(to == from);
TEST_CHECK(to == directory_iterator{});
}
TEST_CASE(test_copy_valid_iterator)
{
const path testDir = StaticEnv::Dir;
const directory_iterator endIt{};
directory_iterator it_obj(testDir);
const directory_iterator& it = it_obj;
TEST_REQUIRE(it != endIt);
++it_obj;
TEST_REQUIRE(it != endIt);
const path entry = *it;
directory_iterator it2(testDir);
TEST_REQUIRE(it2 != it);
const path entry2 = *it2;
TEST_CHECK(entry2 != entry);
it2 = it;
TEST_REQUIRE(it2 == it);
TEST_CHECK(*it2 == entry);
}
TEST_CASE(test_returns_reference_to_self)
{
const directory_iterator it;
directory_iterator it2;
directory_iterator& ref = (it2 = it);
TEST_CHECK(&ref == &it2);
}
TEST_SUITE_END()

View File

@ -0,0 +1,253 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// explicit directory_iterator(const path& p);
// directory_iterator(const path& p, directory_options options);
// directory_iterator(const path& p, error_code& ec);
// directory_iterator(const path& p, directory_options options, error_code& ec);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(directory_iterator_constructor_tests)
TEST_CASE(test_constructor_signatures)
{
using D = directory_iterator;
// explicit directory_iterator(path const&);
static_assert(!std::is_convertible<path, D>::value, "");
static_assert(std::is_constructible<D, path>::value, "");
static_assert(!std::is_nothrow_constructible<D, path>::value, "");
// directory_iterator(path const&, error_code&)
static_assert(std::is_constructible<D, path,
std::error_code&>::value, "");
static_assert(!std::is_nothrow_constructible<D, path,
std::error_code&>::value, "");
// directory_iterator(path const&, directory_options);
static_assert(std::is_constructible<D, path, directory_options>::value, "");
static_assert(!std::is_nothrow_constructible<D, path, directory_options>::value, "");
// directory_iterator(path const&, directory_options, error_code&)
static_assert(std::is_constructible<D, path, directory_options,
std::error_code&>::value, "");
static_assert(!std::is_nothrow_constructible<D, path, directory_options,
std::error_code&>::value, "");
}
TEST_CASE(test_construction_from_bad_path)
{
std::error_code ec;
directory_options opts = directory_options::none;
const directory_iterator endIt;
const path testPaths[] = { StaticEnv::DNE, StaticEnv::BadSymlink };
for (path const& testPath : testPaths)
{
{
directory_iterator it(testPath, ec);
TEST_CHECK(ec);
TEST_CHECK(it == endIt);
}
{
directory_iterator it(testPath, opts, ec);
TEST_CHECK(ec);
TEST_CHECK(it == endIt);
}
{
TEST_CHECK_THROW(filesystem_error, directory_iterator(testPath));
TEST_CHECK_THROW(filesystem_error, directory_iterator(testPath, opts));
}
}
}
TEST_CASE(access_denied_test_case)
{
using namespace fs;
scoped_test_env env;
path const testDir = env.make_env_path("dir1");
path const testFile = testDir / "testFile";
env.create_dir(testDir);
env.create_file(testFile, 42);
// Test that we can iterator over the directory before changing the perms
{
directory_iterator it(testDir);
TEST_REQUIRE(it != directory_iterator{});
}
// Change the permissions so we can no longer iterate
permissions(testDir, perms::none);
// Check that the construction fails when skip_permissions_denied is
// not given.
{
std::error_code ec;
directory_iterator it(testDir, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == directory_iterator{});
}
// Check that construction does not report an error when
// 'skip_permissions_denied' is given.
{
std::error_code ec;
directory_iterator it(testDir, directory_options::skip_permission_denied, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it == directory_iterator{});
}
}
TEST_CASE(access_denied_to_file_test_case)
{
using namespace fs;
scoped_test_env env;
path const testFile = env.make_env_path("file1");
env.create_file(testFile, 42);
// Change the permissions so we can no longer iterate
permissions(testFile, perms::none);
// Check that the construction fails when skip_permissions_denied is
// not given.
{
std::error_code ec;
directory_iterator it(testFile, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == directory_iterator{});
}
// Check that construction still fails when 'skip_permissions_denied' is given
// because we tried to open a file and not a directory.
{
std::error_code ec;
directory_iterator it(testFile, directory_options::skip_permission_denied, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == directory_iterator{});
}
}
TEST_CASE(test_open_on_empty_directory_equals_end)
{
scoped_test_env env;
const path testDir = env.make_env_path("dir1");
env.create_dir(testDir);
const directory_iterator endIt;
{
std::error_code ec;
directory_iterator it(testDir, ec);
TEST_CHECK(!ec);
TEST_CHECK(it == endIt);
}
{
directory_iterator it(testDir);
TEST_CHECK(it == endIt);
}
}
TEST_CASE(test_open_on_directory_succeeds)
{
const path testDir = StaticEnv::Dir;
std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
std::end( StaticEnv::DirIterationList));
const directory_iterator endIt{};
{
std::error_code ec;
directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it != endIt);
TEST_CHECK(dir_contents.count(*it));
}
{
directory_iterator it(testDir);
TEST_CHECK(it != endIt);
TEST_CHECK(dir_contents.count(*it));
}
}
TEST_CASE(test_open_on_file_fails)
{
const path testFile = StaticEnv::File;
const directory_iterator endIt{};
{
std::error_code ec;
directory_iterator it(testFile, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == endIt);
}
{
TEST_CHECK_THROW(filesystem_error, directory_iterator(testFile));
}
}
TEST_CASE(test_open_on_empty_string)
{
const path testPath = "";
const directory_iterator endIt{};
std::error_code ec;
directory_iterator it(testPath, ec);
TEST_CHECK(ec);
TEST_CHECK(it == endIt);
}
TEST_CASE(test_open_on_dot_dir)
{
const path testPath = ".";
std::error_code ec;
directory_iterator it(testPath, ec);
TEST_CHECK(!ec);
}
TEST_CASE(test_open_on_symlink)
{
const path symlinkToDir = StaticEnv::SymlinkToDir;
std::set<path> dir_contents;
for (path const& p : StaticEnv::DirIterationList) {
dir_contents.insert(p.filename());
}
const directory_iterator endIt{};
{
std::error_code ec;
directory_iterator it(symlinkToDir, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it != endIt);
path const& entry = *it;
TEST_CHECK(dir_contents.count(entry.filename()));
}
{
std::error_code ec;
directory_iterator it(symlinkToDir,
directory_options::follow_directory_symlink, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it != endIt);
path const& entry = *it;
TEST_CHECK(dir_contents.count(entry.filename()));
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// directory_iterator::directory_iterator() noexcept
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
int main(int, char**) {
{
static_assert(std::is_nothrow_default_constructible<fs::directory_iterator>::value, "");
}
{
fs::directory_iterator d1;
const fs::directory_iterator d2;
assert(d1 == d2);
}
return 0;
}

View File

@ -0,0 +1,115 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// directory_iterator& operator++();
// directory_iterator& increment(error_code& ec);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
#include <iostream>
using namespace fs;
TEST_SUITE(directory_iterator_increment_tests)
TEST_CASE(test_increment_signatures)
{
directory_iterator d; ((void)d);
std::error_code ec; ((void)ec);
ASSERT_SAME_TYPE(decltype(++d), directory_iterator&);
ASSERT_NOT_NOEXCEPT(++d);
ASSERT_SAME_TYPE(decltype(d.increment(ec)), directory_iterator&);
ASSERT_NOT_NOEXCEPT(d.increment(ec));
}
TEST_CASE(test_prefix_increment)
{
const path testDir = StaticEnv::Dir;
const std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
std::end( StaticEnv::DirIterationList));
const directory_iterator endIt{};
std::error_code ec;
directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
std::set<path> unseen_entries = dir_contents;
while (!unseen_entries.empty()) {
TEST_REQUIRE(it != endIt);
const path entry = *it;
TEST_REQUIRE(unseen_entries.erase(entry) == 1);
directory_iterator& it_ref = ++it;
TEST_CHECK(&it_ref == &it);
}
TEST_CHECK(it == endIt);
}
TEST_CASE(test_postfix_increment)
{
const path testDir = StaticEnv::Dir;
const std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
std::end( StaticEnv::DirIterationList));
const directory_iterator endIt{};
std::error_code ec;
directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
std::set<path> unseen_entries = dir_contents;
while (!unseen_entries.empty()) {
TEST_REQUIRE(it != endIt);
const path entry = *it;
TEST_REQUIRE(unseen_entries.erase(entry) == 1);
const path entry2 = *it++;
TEST_CHECK(entry2 == entry);
}
TEST_CHECK(it == endIt);
}
TEST_CASE(test_increment_method)
{
const path testDir = StaticEnv::Dir;
const std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
std::end( StaticEnv::DirIterationList));
const directory_iterator endIt{};
std::error_code ec;
directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
std::set<path> unseen_entries = dir_contents;
while (!unseen_entries.empty()) {
TEST_REQUIRE(it != endIt);
const path entry = *it;
TEST_REQUIRE(unseen_entries.erase(entry) == 1);
directory_iterator& it_ref = it.increment(ec);
TEST_REQUIRE(!ec);
TEST_CHECK(&it_ref == &it);
}
TEST_CHECK(it == endIt);
}
TEST_SUITE_END()

View File

@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// directory_iterator(directory_iterator&&) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(directory_iterator_move_construct_tests)
TEST_CASE(test_constructor_signature)
{
using D = directory_iterator;
static_assert(std::is_nothrow_move_constructible<D>::value, "");
}
TEST_CASE(test_move_end_iterator)
{
const directory_iterator endIt;
directory_iterator endIt2{};
directory_iterator it(std::move(endIt2));
TEST_CHECK(it == endIt);
TEST_CHECK(endIt2 == endIt);
}
TEST_CASE(test_move_valid_iterator)
{
const path testDir = StaticEnv::Dir;
const directory_iterator endIt{};
directory_iterator it(testDir);
TEST_REQUIRE(it != endIt);
const path entry = *it;
const directory_iterator it2(std::move(it));
TEST_CHECK(*it2 == entry);
TEST_CHECK(it == it2 || it == endIt);
}
TEST_SUITE_END()

View File

@ -0,0 +1,115 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// directory_iterator& operator=(directory_iterator const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
// The filesystem specification explicitly allows for self-move on
// the directory iterators. Turn off this warning so we can test it.
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wself-move"
#endif
using namespace fs;
TEST_SUITE(directory_iterator_move_assign_tests)
TEST_CASE(test_assignment_signature)
{
using D = directory_iterator;
static_assert(std::is_nothrow_move_assignable<D>::value, "");
}
TEST_CASE(test_move_to_end_iterator)
{
const path testDir = StaticEnv::Dir;
directory_iterator from(testDir);
TEST_REQUIRE(from != directory_iterator{});
const path entry = *from;
directory_iterator to{};
to = std::move(from);
TEST_REQUIRE(to != directory_iterator{});
TEST_CHECK(*to == entry);
}
TEST_CASE(test_move_from_end_iterator)
{
const path testDir = StaticEnv::Dir;
directory_iterator from{};
directory_iterator to(testDir);
TEST_REQUIRE(to != from);
to = std::move(from);
TEST_REQUIRE(to == directory_iterator{});
TEST_REQUIRE(from == directory_iterator{});
}
TEST_CASE(test_move_valid_iterator)
{
const path testDir = StaticEnv::Dir;
const directory_iterator endIt{};
directory_iterator it(testDir);
TEST_REQUIRE(it != endIt);
++it;
TEST_REQUIRE(it != endIt);
const path entry = *it;
directory_iterator it2(testDir);
TEST_REQUIRE(it2 != it);
const path entry2 = *it2;
TEST_CHECK(entry2 != entry);
it2 = std::move(it);
TEST_REQUIRE(it2 != directory_iterator{});
TEST_CHECK(*it2 == entry);
}
TEST_CASE(test_returns_reference_to_self)
{
directory_iterator it;
directory_iterator it2;
directory_iterator& ref = (it2 = it);
TEST_CHECK(&ref == &it2);
}
TEST_CASE(test_self_move)
{
// Create two non-equal iterators that have exactly the same state.
directory_iterator it(StaticEnv::Dir);
directory_iterator it2(StaticEnv::Dir);
++it; ++it2;
TEST_CHECK(it != it2);
TEST_CHECK(*it2 == *it);
it = std::move(it);
TEST_CHECK(*it2 == *it);
}
TEST_SUITE_END()

View File

@ -0,0 +1,59 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// directory_iterator begin(directory_iterator iter) noexcept;
// directory_iterator end(directory_iterator iter) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
#include <iostream>
using namespace fs;
TEST_SUITE(directory_iterator_begin_end_tests)
TEST_CASE(test_function_signatures)
{
directory_iterator d; ((void)d);
ASSERT_SAME_TYPE(decltype(begin(d)), directory_iterator);
ASSERT_NOEXCEPT(begin(std::move(d)));
ASSERT_SAME_TYPE(decltype(end(d)), directory_iterator);
ASSERT_NOEXCEPT(end(std::move(d)));
}
TEST_CASE(test_ranged_for_loop)
{
const path testDir = StaticEnv::Dir;
std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
std::end( StaticEnv::DirIterationList));
std::error_code ec;
directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
for (auto& elem : it) {
TEST_CHECK(dir_contents.erase(elem) == 1);
}
TEST_CHECK(dir_contents.empty());
}
TEST_SUITE_END()

View File

@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
// typedef ... value_type;
// typedef ... difference_type;
// typedef ... pointer;
// typedef ... reference;
// typedef ... iterator_category
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
int main(int, char**) {
using namespace fs;
using D = directory_iterator;
ASSERT_SAME_TYPE(D::value_type, directory_entry);
ASSERT_SAME_TYPE(D::difference_type, std::ptrdiff_t);
ASSERT_SAME_TYPE(D::pointer, const directory_entry*);
ASSERT_SAME_TYPE(D::reference, const directory_entry&);
ASSERT_SAME_TYPE(D::iterator_category, std::input_iterator_tag);
return 0;
}

View File

@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class file_status
// explicit file_status() noexcept;
// explicit file_status(file_type, perms prms = perms::unknown) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_convertible.hpp"
int main(int, char**) {
using namespace fs;
// Default ctor
{
static_assert(std::is_nothrow_default_constructible<file_status>::value,
"The default constructor must be noexcept");
static_assert(test_convertible<file_status>(),
"The default constructor must not be explicit");
const file_status f;
assert(f.type() == file_type::none);
assert(f.permissions() == perms::unknown);
}
// Unary ctor
{
static_assert(std::is_nothrow_constructible<file_status, file_type>::value,
"This constructor must be noexcept");
static_assert(!test_convertible<file_status, file_type>(),
"This constructor must be explicit");
const file_status f(file_type::not_found);
assert(f.type() == file_type::not_found);
assert(f.permissions() == perms::unknown);
}
// Binary ctor
{
static_assert(std::is_nothrow_constructible<file_status, file_type, perms>::value,
"This constructor must be noexcept");
static_assert(!test_convertible<file_status, file_type, perms>(),
"This constructor must b explicit");
const file_status f(file_type::regular, perms::owner_read);
assert(f.type() == file_type::regular);
assert(f.permissions() == perms::owner_read);
}
return 0;
}

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class file_status
// void type(file_type) noexcept;
// void permissions(perms) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
int main(int, char**) {
using namespace fs;
file_status st;
// type test
{
static_assert(noexcept(st.type(file_type::regular)),
"operation must be noexcept");
static_assert(std::is_same<decltype(st.type(file_type::regular)), void>::value,
"operation must return void");
assert(st.type() != file_type::regular);
st.type(file_type::regular);
assert(st.type() == file_type::regular);
}
// permissions test
{
static_assert(noexcept(st.permissions(perms::owner_read)),
"operation must be noexcept");
static_assert(std::is_same<decltype(st.permissions(perms::owner_read)), void>::value,
"operation must return void");
assert(st.permissions() != perms::owner_read);
st.permissions(perms::owner_read);
assert(st.permissions() == perms::owner_read);
}
return 0;
}

View File

@ -0,0 +1,46 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class file_status
// file_type type() const noexcept;
// perms permissions(p) const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
int main(int, char**) {
using namespace fs;
const file_status st(file_type::regular, perms::owner_read);
// type test
{
static_assert(noexcept(st.type()),
"operation must be noexcept");
static_assert(std::is_same<decltype(st.type()), file_type>::value,
"operation must return file_type");
assert(st.type() == file_type::regular);
}
// permissions test
{
static_assert(noexcept(st.permissions()),
"operation must be noexcept");
static_assert(std::is_same<decltype(st.permissions()), perms>::value,
"operation must return perms");
assert(st.permissions() == perms::owner_read);
}
return 0;
}

View File

@ -0,0 +1,103 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class filesystem_error
// filesystem_error(const string& what_arg, error_code ec);
// filesystem_error(const string& what_arg, const path& p1, error_code ec);
// filesystem_error(const string& what_arg, const path& p1, const path& p2, error_code ec);
// const std::error_code& code() const;
// const char* what() const noexcept;
// const path& path1() const noexcept;
// const path& path2() const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
void test_constructors() {
using namespace fs;
// The string returned by "filesystem_error::what() must contain runtime_error::what()
const std::string what_arg = "Hello World";
const std::string what_contains = std::runtime_error(what_arg).what();
assert(what_contains.find(what_arg) != std::string::npos);
auto CheckWhat = [what_contains](filesystem_error const& e) {
std::string s = e.what();
assert(s.find(what_contains) != std::string::npos);
};
std::error_code ec = std::make_error_code(std::errc::file_exists);
const path p1("foo");
const path p2("bar");
// filesystem_error(const string& what_arg, error_code ec);
{
ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, ec));
filesystem_error e(what_arg, ec);
CheckWhat(e);
assert(e.code() == ec);
assert(e.path1().empty() && e.path2().empty());
}
// filesystem_error(const string& what_arg, const path&, error_code ec);
{
ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, p1, ec));
filesystem_error e(what_arg, p1, ec);
CheckWhat(e);
assert(e.code() == ec);
assert(e.path1() == p1);
assert(e.path2().empty());
}
// filesystem_error(const string& what_arg, const path&, const path&, error_code ec);
{
ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, p1, p2, ec));
filesystem_error e(what_arg, p1, p2, ec);
CheckWhat(e);
assert(e.code() == ec);
assert(e.path1() == p1);
assert(e.path2() == p2);
}
}
void test_signatures()
{
using namespace fs;
const path p;
std::error_code ec;
const filesystem_error e("lala", ec);
// const path& path1() const noexcept;
{
ASSERT_SAME_TYPE(path const&, decltype(e.path1()));
ASSERT_NOEXCEPT(e.path1());
}
// const path& path2() const noexcept
{
ASSERT_SAME_TYPE(path const&, decltype(e.path2()));
ASSERT_NOEXCEPT(e.path2());
}
// const char* what() const noexcept
{
ASSERT_SAME_TYPE(const char*, decltype(e.what()));
ASSERT_NOEXCEPT(e.what());
}
}
int main(int, char**) {
static_assert(std::is_base_of<std::system_error, fs::filesystem_error>::value, "");
test_constructors();
test_signatures();
return 0;
}

View File

@ -0,0 +1,106 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// template <class Source>
// path(const Source& source);
// template <class InputIterator>
// path(InputIterator first, InputIterator last);
#include "filesystem_include.hpp"
#include <iterator>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "filesystem_test_helper.hpp"
template <class It>
std::reverse_iterator<It> mkRev(It it) {
return std::reverse_iterator<It>(it);
}
void checkIteratorConcepts() {
using namespace fs;
using It = path::iterator;
using Traits = std::iterator_traits<It>;
ASSERT_SAME_TYPE(Traits::iterator_category, std::bidirectional_iterator_tag);
ASSERT_SAME_TYPE(Traits::value_type, path);
ASSERT_SAME_TYPE(Traits::pointer, path const*);
ASSERT_SAME_TYPE(Traits::reference, path const&);
{
It it;
ASSERT_SAME_TYPE(It&, decltype(++it));
ASSERT_SAME_TYPE(It, decltype(it++));
ASSERT_SAME_TYPE(It&, decltype(--it));
ASSERT_SAME_TYPE(It, decltype(it--));
ASSERT_SAME_TYPE(Traits::reference, decltype(*it));
ASSERT_SAME_TYPE(Traits::pointer, decltype(it.operator->()));
ASSERT_SAME_TYPE(std::string const&, decltype(it->native()));
ASSERT_SAME_TYPE(bool, decltype(it == it));
ASSERT_SAME_TYPE(bool, decltype(it != it));
}
{
path const p;
ASSERT_SAME_TYPE(It, decltype(p.begin()));
ASSERT_SAME_TYPE(It, decltype(p.end()));
assert(p.begin() == p.end());
}
}
void checkBeginEndBasic() {
using namespace fs;
using It = path::iterator;
{
path const p;
ASSERT_SAME_TYPE(It, decltype(p.begin()));
ASSERT_SAME_TYPE(It, decltype(p.end()));
assert(p.begin() == p.end());
}
{
path const p("foo");
It default_constructed;
default_constructed = p.begin();
assert(default_constructed == p.begin());
assert(default_constructed != p.end());
default_constructed = p.end();
assert(default_constructed == p.end());
assert(default_constructed != p.begin());
}
{
path p("//root_name//first_dir////second_dir");
const path expect[] = {"/", "root_name", "first_dir", "second_dir"};
assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
assert(checkCollectionsEqualBackwards(p.begin(), p.end(), std::begin(expect), std::end(expect)));
}
{
path p("////foo/bar/baz///");
const path expect[] = {"/", "foo", "bar", "baz", ""};
assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
assert(checkCollectionsEqualBackwards(p.begin(), p.end(), std::begin(expect), std::end(expect)));
}
}
int main(int, char**) {
using namespace fs;
checkIteratorConcepts();
checkBeginEndBasic(); // See path.decompose.pass.cpp for more tests.
return 0;
}

View File

@ -0,0 +1,340 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& operator/=(path const&)
// template <class Source>
// path& operator/=(Source const&);
// template <class Source>
// path& append(Source const&);
// template <class InputIterator>
// path& append(InputIterator first, InputIterator last);
#include "filesystem_include.hpp"
#include <type_traits>
#include <string_view>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
#include "verbose_assert.h"
struct AppendOperatorTestcase {
MultiStringType lhs;
MultiStringType rhs;
MultiStringType expect;
};
#define S(Str) MKSTR(Str)
const AppendOperatorTestcase Cases[] =
{
{S(""), S(""), S("")}
, {S("p1"), S("p2"), S("p1/p2")}
, {S("p1/"), S("p2"), S("p1/p2")}
, {S("p1"), S("/p2"), S("/p2")}
, {S("p1/"), S("/p2"), S("/p2")}
, {S("p1"), S("\\p2"), S("p1/\\p2")}
, {S("p1\\"), S("p2"), S("p1\\/p2")}
, {S("p1\\"), S("\\p2"), S("p1\\/\\p2")}
, {S(""), S("p2"), S("p2")}
, {S("/p1"), S("p2"), S("/p1/p2")}
, {S("/p1"), S("/p2"), S("/p2")}
, {S("/p1/p3"), S("p2"), S("/p1/p3/p2")}
, {S("/p1/p3/"), S("p2"), S("/p1/p3/p2")}
, {S("/p1/"), S("p2"), S("/p1/p2")}
, {S("/p1/p3/"), S("/p2/p4"), S("/p2/p4")}
, {S("/"), S(""), S("/")}
, {S("/p1"), S("/p2/"), S("/p2/")}
, {S("p1"), S(""), S("p1/")}
, {S("p1/"), S(""), S("p1/")}
};
const AppendOperatorTestcase LongLHSCases[] =
{
{S("p1"), S("p2"), S("p1/p2")}
, {S("p1/"), S("p2"), S("p1/p2")}
, {S("p1"), S("/p2"), S("/p2")}
, {S("/p1"), S("p2"), S("/p1/p2")}
};
#undef S
// The append operator may need to allocate a temporary buffer before a code_cvt
// conversion. Test if this allocation occurs by:
// 1. Create a path, `LHS`, and reserve enough space to append `RHS`.
// This prevents `LHS` from allocating during the actual appending.
// 2. Create a `Source` object `RHS`, which represents a "large" string.
// (The string must not trigger the SSO)
// 3. Append `RHS` to `LHS` and check for the expected allocation behavior.
template <class CharT>
void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
{
using namespace fs;
using Ptr = CharT const*;
using Str = std::basic_string<CharT>;
using StrView = std::basic_string_view<CharT>;
using InputIter = input_iterator<Ptr>;
const Ptr L = TC.lhs;
Str RShort = (Ptr)TC.rhs;
Str EShort = (Ptr)TC.expect;
assert(RShort.size() >= 2);
CharT c = RShort.back();
RShort.append(100, c);
EShort.append(100, c);
const Ptr R = RShort.data();
const Str& E = EShort;
std::size_t ReserveSize = E.size() + 3;
// basic_string
{
path LHS(L); PathReserve(LHS, ReserveSize);
Str RHS(R);
{
DisableAllocationGuard g;
LHS /= RHS;
}
ASSERT_PRED(PathEq, LHS , E);
}
// basic_string_view
{
path LHS(L); PathReserve(LHS, ReserveSize);
StrView RHS(R);
{
DisableAllocationGuard g;
LHS /= RHS;
}
assert(PathEq(LHS, E));
}
// CharT*
{
path LHS(L); PathReserve(LHS, ReserveSize);
Ptr RHS(R);
{
DisableAllocationGuard g;
LHS /= RHS;
}
assert(PathEq(LHS, E));
}
{
path LHS(L); PathReserve(LHS, ReserveSize);
Ptr RHS(R);
{
DisableAllocationGuard g;
LHS.append(RHS, StrEnd(RHS));
}
assert(PathEq(LHS, E));
}
// input iterator - For non-native char types, appends needs to copy the
// iterator range into a contiguous block of memory before it can perform the
// code_cvt conversions.
// For "char" no allocations will be performed because no conversion is
// required.
bool DisableAllocations = std::is_same<CharT, char>::value;
{
path LHS(L); PathReserve(LHS, ReserveSize);
InputIter RHS(R);
{
RequireAllocationGuard g; // requires 1 or more allocations occur by default
if (DisableAllocations) g.requireExactly(0);
LHS /= RHS;
}
assert(PathEq(LHS, E));
}
{
path LHS(L); PathReserve(LHS, ReserveSize);
InputIter RHS(R);
InputIter REnd(StrEnd(R));
{
RequireAllocationGuard g;
if (DisableAllocations) g.requireExactly(0);
LHS.append(RHS, REnd);
}
assert(PathEq(LHS, E));
}
}
template <class CharT>
void doAppendSourceTest(AppendOperatorTestcase const& TC)
{
using namespace fs;
using Ptr = CharT const*;
using Str = std::basic_string<CharT>;
using StrView = std::basic_string_view<CharT>;
using InputIter = input_iterator<Ptr>;
const Ptr L = TC.lhs;
const Ptr R = TC.rhs;
const Ptr E = TC.expect;
// basic_string
{
path Result(L);
Str RHS(R);
path& Ref = (Result /= RHS);
ASSERT_EQ(Result, E)
<< DISPLAY(L) << DISPLAY(R);
assert(&Ref == &Result);
}
{
path LHS(L);
Str RHS(R);
path& Ref = LHS.append(RHS);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
// basic_string_view
{
path LHS(L);
StrView RHS(R);
path& Ref = (LHS /= RHS);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
{
path LHS(L);
StrView RHS(R);
path& Ref = LHS.append(RHS);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
// Char*
{
path LHS(L);
Str RHS(R);
path& Ref = (LHS /= RHS);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
{
path LHS(L);
Ptr RHS(R);
path& Ref = LHS.append(RHS);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
{
path LHS(L);
Ptr RHS(R);
path& Ref = LHS.append(RHS, StrEnd(RHS));
ASSERT_PRED(PathEq, LHS, E)
<< DISPLAY(L) << DISPLAY(R);
assert(&Ref == &LHS);
}
// iterators
{
path LHS(L);
InputIter RHS(R);
path& Ref = (LHS /= RHS);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
{
path LHS(L); InputIter RHS(R);
path& Ref = LHS.append(RHS);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
{
path LHS(L);
InputIter RHS(R);
InputIter REnd(StrEnd(R));
path& Ref = LHS.append(RHS, REnd);
assert(PathEq(LHS, E));
assert(&Ref == &LHS);
}
}
template <class It, class = decltype(fs::path{}.append(std::declval<It>()))>
constexpr bool has_append(int) { return true; }
template <class It>
constexpr bool has_append(long) { return false; }
template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))>
constexpr bool has_append_op(int) { return true; }
template <class It>
constexpr bool has_append_op(long) { return false; }
template <class It>
constexpr bool has_append() {
static_assert(has_append<It>(0) == has_append_op<It>(0), "must be same");
return has_append<It>(0) && has_append_op<It>(0);
}
void test_sfinae()
{
using namespace fs;
{
using It = const char* const;
static_assert(has_append<It>(), "");
}
{
using It = input_iterator<const char*>;
static_assert(has_append<It>(), "");
}
{
struct Traits {
using iterator_category = std::input_iterator_tag;
using value_type = const char;
using pointer = const char*;
using reference = const char&;
using difference_type = std::ptrdiff_t;
};
using It = input_iterator<const char*, Traits>;
static_assert(has_append<It>(), "");
}
{
using It = output_iterator<const char*>;
static_assert(!has_append<It>(), "");
}
{
static_assert(!has_append<int*>(), "");
}
{
static_assert(!has_append<char>(), "");
static_assert(!has_append<const char>(), "");
}
}
int main(int, char**)
{
using namespace fs;
for (auto const & TC : Cases) {
{
const char* LHS_In = TC.lhs;
const char* RHS_In = TC.rhs;
path LHS(LHS_In);
path RHS(RHS_In);
path& Res = (LHS /= RHS);
ASSERT_PRED(PathEq, Res, (const char*)TC.expect)
<< DISPLAY(LHS_In) << DISPLAY(RHS_In);
assert(&Res == &LHS);
}
doAppendSourceTest<char> (TC);
doAppendSourceTest<wchar_t> (TC);
doAppendSourceTest<char16_t>(TC);
doAppendSourceTest<char32_t>(TC);
}
for (auto const & TC : LongLHSCases) {
doAppendSourceAllocTest<char>(TC);
doAppendSourceAllocTest<wchar_t>(TC);
}
test_sfinae();
return 0;
}

View File

@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& operator=(path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "count_new.hpp"
int main(int, char**) {
using namespace fs;
path p("abc");
p = {};
assert(p.native() == "");
return 0;
}

View File

@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& operator=(path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
int main(int, char**) {
using namespace fs;
static_assert(std::is_copy_assignable<path>::value, "");
static_assert(!std::is_nothrow_copy_assignable<path>::value, "should not be noexcept");
const std::string s("foo");
const path p(s);
path p2;
path& pref = (p2 = p);
assert(p.native() == s);
assert(p2.native() == s);
assert(&pref == &p2);
return 0;
}

View File

@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& operator=(path&&) noexcept
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "count_new.hpp"
int main(int, char**) {
using namespace fs;
static_assert(std::is_nothrow_move_assignable<path>::value, "");
assert(globalMemCounter.checkOutstandingNewEq(0));
const std::string s("we really really really really really really really "
"really really long string so that we allocate");
assert(globalMemCounter.checkOutstandingNewEq(1));
path p(s);
{
DisableAllocationGuard g;
path p2;
path& pref = (p2 = std::move(p));
assert(p2.native() == s);
assert(p.native() != s); // Testing moved from state
assert(&pref == &p2);
}
return 0;
}

View File

@ -0,0 +1,242 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// template <class Source>
// path& operator=(Source const&);
// path& operator=(string_type&&);
// template <class Source>
// path& assign(Source const&);
// template <class InputIterator>
// path& assign(InputIterator first, InputIterator last);
#include "filesystem_include.hpp"
#include <type_traits>
#include <string_view>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
#include <iostream>
template <class CharT>
void RunTestCase(MultiStringType const& MS) {
using namespace fs;
const char* Expect = MS;
const CharT* TestPath = MS;
const CharT* TestPathEnd = StrEnd(TestPath);
const std::size_t Size = TestPathEnd - TestPath;
const std::size_t SSize = StrEnd(Expect) - Expect;
assert(Size == SSize);
//////////////////////////////////////////////////////////////////////////////
// basic_string<Char, Traits, Alloc>
{
const std::basic_string<CharT> S(TestPath);
path p; PathReserve(p, S.length() + 1);
{
// string provides a contiguous iterator. No allocation needed.
DisableAllocationGuard g;
path& pref = (p = S);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
assert(p.string<CharT>() == S);
}
{
const std::basic_string<CharT> S(TestPath);
path p; PathReserve(p, S.length() + 1);
{
DisableAllocationGuard g;
path& pref = p.assign(S);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
assert(p.string<CharT>() == S);
}
// basic_string<Char, Traits, Alloc>
{
const std::basic_string_view<CharT> S(TestPath);
path p; PathReserve(p, S.length() + 1);
{
// string provides a contiguous iterator. No allocation needed.
DisableAllocationGuard g;
path& pref = (p = S);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
assert(p.string<CharT>() == S);
}
{
const std::basic_string_view<CharT> S(TestPath);
path p; PathReserve(p, S.length() + 1);
{
DisableAllocationGuard g;
path& pref = p.assign(S);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
assert(p.string<CharT>() == S);
}
//////////////////////////////////////////////////////////////////////////////
// Char* pointers
{
path p; PathReserve(p, Size + 1);
{
// char* pointers are contiguous and can be used with code_cvt directly.
// no allocations needed.
DisableAllocationGuard g;
path& pref = (p = TestPath);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
{
path p; PathReserve(p, Size + 1);
{
DisableAllocationGuard g;
path& pref = p.assign(TestPath);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
{
path p; PathReserve(p, Size + 1);
{
DisableAllocationGuard g;
path& pref = p.assign(TestPath, TestPathEnd);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
//////////////////////////////////////////////////////////////////////////////
// Iterators
{
using It = input_iterator<const CharT*>;
path p; PathReserve(p, Size + 1);
It it(TestPath);
{
// Iterators cannot be used with code_cvt directly. This assignment
// may allocate if it's larger than a "short-string".
path& pref = (p = it);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
{
using It = input_iterator<const CharT*>;
path p; PathReserve(p, Size + 1);
It it(TestPath);
{
path& pref = p.assign(it);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
{
using It = input_iterator<const CharT*>;
path p; PathReserve(p, Size + 1);
It it(TestPath);
It e(TestPathEnd);
{
path& pref = p.assign(it, e);
assert(&pref == &p);
}
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
}
template <class It, class = decltype(fs::path{}.assign(std::declval<It>()))>
constexpr bool has_assign(int) { return true; }
template <class It>
constexpr bool has_assign(long) { return false; }
template <class It>
constexpr bool has_assign() { return has_assign<It>(0); }
void test_sfinae() {
using namespace fs;
{
using It = const char* const;
static_assert(std::is_assignable<path, It>::value, "");
static_assert(has_assign<It>(), "");
}
{
using It = input_iterator<const char*>;
static_assert(std::is_assignable<path, It>::value, "");
static_assert(has_assign<It>(), "");
}
{
struct Traits {
using iterator_category = std::input_iterator_tag;
using value_type = const char;
using pointer = const char*;
using reference = const char&;
using difference_type = std::ptrdiff_t;
};
using It = input_iterator<const char*, Traits>;
static_assert(std::is_assignable<path, It>::value, "");
static_assert(has_assign<It>(), "");
}
{
using It = output_iterator<const char*>;
static_assert(!std::is_assignable<path, It>::value, "");
static_assert(!has_assign<It>(), "");
}
{
static_assert(!std::is_assignable<path, int*>::value, "");
static_assert(!has_assign<int*>(), "");
}
}
void RunStringMoveTest(const char* Expect) {
using namespace fs;
std::string ss(Expect);
path p;
{
DisableAllocationGuard g; ((void)g);
path& pr = (p = std::move(ss));
assert(&pr == &p);
}
assert(p == Expect);
{
// Signature test
ASSERT_NOEXCEPT(p = std::move(ss));
}
}
int main(int, char**) {
for (auto const& MS : PathList) {
RunTestCase<char>(MS);
RunTestCase<wchar_t>(MS);
RunTestCase<char16_t>(MS);
RunTestCase<char32_t>(MS);
RunStringMoveTest(MS);
}
test_sfinae();
return 0;
}

View File

@ -0,0 +1,192 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// int compare(path const&) const noexcept;
// int compare(string_type const&) const;
// int compare(value_type const*) const;
//
// bool operator==(path const&, path const&) noexcept;
// bool operator!=(path const&, path const&) noexcept;
// bool operator< (path const&, path const&) noexcept;
// bool operator<=(path const&, path const&) noexcept;
// bool operator> (path const&, path const&) noexcept;
// bool operator>=(path const&, path const&) noexcept;
//
// size_t hash_value(path const&) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <vector>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
#include "verbose_assert.h"
struct PathCompareTest {
const char* LHS;
const char* RHS;
int expect;
};
#define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
#define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
#define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
#define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
const PathCompareTest CompareTestCases[] =
{
{"", "", 0},
{"a", "", 1},
{"", "a", -1},
{"a/b/c", "a/b/c", 0},
{"b/a/c", "a/b/c", 1},
{"a/b/c", "b/a/c", -1},
{"a/b", "a/b/c", -1},
{"a/b/c", "a/b", 1},
{"a/b/", "a/b/.", -1},
{"a/b/", "a/b", 1},
{"a/b//////", "a/b/////.", -1},
{"a/.././b", "a///..//.////b", 0},
{"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators
{"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory
{"/foo/bar/", "/foo/bar", 1}, // trailing separator
{"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0.
{"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0.
{"//" LONGA "////" LONGB "/" LONGC "///" LONGD, "//" LONGA "/" LONGB "/" LONGC "/" LONGD, 0},
{ LONGA "/" LONGB "/" LONGC, LONGA "/" LONGB "/" LONGB, 1}
};
#undef LONGA
#undef LONGB
#undef LONGC
#undef LONGD
static inline int normalize_ret(int ret)
{
return ret < 0 ? -1 : (ret > 0 ? 1 : 0);
}
void test_compare_basic()
{
using namespace fs;
for (auto const & TC : CompareTestCases) {
const path p1(TC.LHS);
const path p2(TC.RHS);
const std::string R(TC.RHS);
const std::string_view RV(TC.RHS);
const int E = TC.expect;
{ // compare(...) functions
DisableAllocationGuard g; // none of these operations should allocate
// check runtime results
int ret1 = normalize_ret(p1.compare(p2));
int ret2 = normalize_ret(p1.compare(R));
int ret3 = normalize_ret(p1.compare(TC.RHS));
int ret4 = normalize_ret(p1.compare(RV));
g.release();
ASSERT_EQ(ret1, ret2);
ASSERT_EQ(ret1, ret3);
ASSERT_EQ(ret1, ret4);
ASSERT_EQ(ret1, E)
<< DISPLAY(TC.LHS) << DISPLAY(TC.RHS);
// check signatures
ASSERT_NOEXCEPT(p1.compare(p2));
}
{ // comparison operators
DisableAllocationGuard g; // none of these operations should allocate
// Check runtime result
assert((p1 == p2) == (E == 0));
assert((p1 != p2) == (E != 0));
assert((p1 < p2) == (E < 0));
assert((p1 <= p2) == (E <= 0));
assert((p1 > p2) == (E > 0));
assert((p1 >= p2) == (E >= 0));
// Check signatures
ASSERT_NOEXCEPT(p1 == p2);
ASSERT_NOEXCEPT(p1 != p2);
ASSERT_NOEXCEPT(p1 < p2);
ASSERT_NOEXCEPT(p1 <= p2);
ASSERT_NOEXCEPT(p1 > p2);
ASSERT_NOEXCEPT(p1 >= p2);
}
{ // check hash values
auto h1 = hash_value(p1);
auto h2 = hash_value(p2);
assert((h1 == h2) == (p1 == p2));
// check signature
ASSERT_SAME_TYPE(size_t, decltype(hash_value(p1)));
ASSERT_NOEXCEPT(hash_value(p1));
}
}
}
int CompareElements(std::vector<std::string> const& LHS, std::vector<std::string> const& RHS) {
bool IsLess = std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(), RHS.end());
if (IsLess)
return -1;
bool IsGreater = std::lexicographical_compare(RHS.begin(), RHS.end(), LHS.begin(), LHS.end());
if (IsGreater)
return 1;
return 0;
}
void test_compare_elements() {
struct {
std::vector<std::string> LHSElements;
std::vector<std::string> RHSElements;
int Expect;
} TestCases[] = {
{{"a"}, {"a"}, 0},
{{"a"}, {"b"}, -1},
{{"b"}, {"a"}, 1},
{{"a", "b", "c"}, {"a", "b", "c"}, 0},
{{"a", "b", "c"}, {"a", "b", "d"}, -1},
{{"a", "b", "d"}, {"a", "b", "c"}, 1},
{{"a", "b"}, {"a", "b", "c"}, -1},
{{"a", "b", "c"}, {"a", "b"}, 1},
};
auto BuildPath = [](std::vector<std::string> const& Elems) {
fs::path p;
for (auto &E : Elems)
p /= E;
return p;
};
for (auto &TC : TestCases) {
fs::path LHS = BuildPath(TC.LHSElements);
fs::path RHS = BuildPath(TC.RHSElements);
const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements);
assert(ExpectCmp == TC.Expect);
const int GotCmp = normalize_ret(LHS.compare(RHS));
assert(GotCmp == TC.Expect);
}
}
int main(int, char**) {
test_compare_basic();
test_compare_elements();
return 0;
}

View File

@ -0,0 +1,389 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& operator+=(const path& x);
// path& operator+=(const string_type& x);
// path& operator+=(string_view x);
// path& operator+=(const value_type* x);
// path& operator+=(value_type x);
// template <class Source>
// path& operator+=(const Source& x);
// template <class EcharT>
// path& operator+=(EcharT x);
// template <class Source>
// path& concat(const Source& x);
// template <class InputIterator>
// path& concat(InputIterator first, InputIterator last);
#include "filesystem_include.hpp"
#include <type_traits>
#include <string>
#include <string_view>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
struct ConcatOperatorTestcase {
MultiStringType lhs;
MultiStringType rhs;
MultiStringType expect;
};
#define LONGSTR "LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR"
#define S(Str) MKSTR(Str)
const ConcatOperatorTestcase Cases[] =
{
{S(""), S(""), S("")}
, {S("p1"), S("p2"), S("p1p2")}
, {S("p1/"), S("/p2"), S("p1//p2")}
, {S(""), S("\\foo/bar/baz"), S("\\foo/bar/baz")}
, {S("c:\\foo"), S(""), S("c:\\foo")}
, {S(LONGSTR), S("foo"), S(LONGSTR "foo")}
, {S("abcdefghijklmnopqrstuvwxyz/\\"), S("/\\123456789"), S("abcdefghijklmnopqrstuvwxyz/\\/\\123456789")}
};
const ConcatOperatorTestcase LongLHSCases[] =
{
{S(""), S(LONGSTR), S(LONGSTR)}
, {S("p1/"), S(LONGSTR), S("p1/" LONGSTR)}
};
const ConcatOperatorTestcase CharTestCases[] =
{
{S(""), S("P"), S("P")}
, {S("/fooba"), S("r"), S("/foobar")}
};
#undef S
#undef LONGSTR
// The concat operator may need to allocate a temporary buffer before a code_cvt
// conversion. Test if this allocation occurs by:
// 1. Create a path, `LHS`, and reserve enough space to append `RHS`.
// This prevents `LHS` from allocating during the actual appending.
// 2. Create a `Source` object `RHS`, which represents a "large" string.
// (The string must not trigger the SSO)
// 3. Concat `RHS` to `LHS` and check for the expected allocation behavior.
template <class CharT>
void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC)
{
using namespace fs;
using Ptr = CharT const*;
using Str = std::basic_string<CharT>;
using StrView = std::basic_string_view<CharT>;
using InputIter = input_iterator<Ptr>;
const Ptr L = TC.lhs;
const Ptr R = TC.rhs;
const Ptr E = TC.expect;
std::size_t ReserveSize = StrLen(E) + 1;
// basic_string
{
path LHS(L); PathReserve(LHS, ReserveSize);
Str RHS(R);
{
DisableAllocationGuard g;
LHS += RHS;
}
assert(LHS == E);
}
// basic_string_view
{
path LHS(L); PathReserve(LHS, ReserveSize);
StrView RHS(R);
{
DisableAllocationGuard g;
LHS += RHS;
}
assert(LHS == E);
}
// CharT*
{
path LHS(L); PathReserve(LHS, ReserveSize);
Ptr RHS(R);
{
DisableAllocationGuard g;
LHS += RHS;
}
assert(LHS == E);
}
{
path LHS(L); PathReserve(LHS, ReserveSize);
Ptr RHS(R);
{
DisableAllocationGuard g;
LHS.concat(RHS, StrEnd(RHS));
}
assert(LHS == E);
}
// input iterator - For non-native char types, appends needs to copy the
// iterator range into a contiguous block of memory before it can perform the
// code_cvt conversions.
// For "char" no allocations will be performed because no conversion is
// required.
bool DisableAllocations = std::is_same<CharT, char>::value;
{
path LHS(L); PathReserve(LHS, ReserveSize);
InputIter RHS(R);
{
RequireAllocationGuard g; // requires 1 or more allocations occur by default
if (DisableAllocations) g.requireExactly(0);
LHS += RHS;
}
assert(LHS == E);
}
{
path LHS(L); PathReserve(LHS, ReserveSize);
InputIter RHS(R);
InputIter REnd(StrEnd(R));
{
RequireAllocationGuard g;
if (DisableAllocations) g.requireExactly(0);
LHS.concat(RHS, REnd);
}
assert(LHS == E);
}
}
template <class CharT>
void doConcatSourceTest(ConcatOperatorTestcase const& TC)
{
using namespace fs;
using Ptr = CharT const*;
using Str = std::basic_string<CharT>;
using StrView = std::basic_string_view<CharT>;
using InputIter = input_iterator<Ptr>;
const Ptr L = TC.lhs;
const Ptr R = TC.rhs;
const Ptr E = TC.expect;
// basic_string
{
path LHS(L);
Str RHS(R);
path& Ref = (LHS += RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
{
path LHS(L);
Str RHS(R);
path& Ref = LHS.concat(RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
// basic_string_view
{
path LHS(L);
StrView RHS(R);
path& Ref = (LHS += RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
{
path LHS(L);
StrView RHS(R);
path& Ref = LHS.concat(RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
// Char*
{
path LHS(L);
Str RHS(R);
path& Ref = (LHS += RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
{
path LHS(L);
Ptr RHS(R);
path& Ref = LHS.concat(RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
{
path LHS(L);
Ptr RHS(R);
path& Ref = LHS.concat(RHS, StrEnd(RHS));
assert(LHS == E);
assert(&Ref == &LHS);
}
// iterators
{
path LHS(L);
InputIter RHS(R);
path& Ref = (LHS += RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
{
path LHS(L); InputIter RHS(R);
path& Ref = LHS.concat(RHS);
assert(LHS == E);
assert(&Ref == &LHS);
}
{
path LHS(L);
InputIter RHS(R);
InputIter REnd(StrEnd(R));
path& Ref = LHS.concat(RHS, REnd);
assert(LHS == E);
assert(&Ref == &LHS);
}
}
template <class CharT>
void doConcatECharTest(ConcatOperatorTestcase const& TC)
{
using namespace fs;
using Ptr = CharT const*;
const Ptr RStr = TC.rhs;
assert(StrLen(RStr) == 1);
const Ptr L = TC.lhs;
const CharT R = RStr[0];
const Ptr E = TC.expect;
{
path LHS(L);
path& Ref = (LHS += R);
assert(LHS == E);
assert(&Ref == &LHS);
}
}
template <class It, class = decltype(fs::path{}.concat(std::declval<It>()))>
constexpr bool has_concat(int) { return true; }
template <class It>
constexpr bool has_concat(long) { return false; }
template <class It, class = decltype(fs::path{}.operator+=(std::declval<It>()))>
constexpr bool has_concat_op(int) { return true; }
template <class It>
constexpr bool has_concat_op(long) { return false; }
template <class It>
constexpr bool has_concat_op() { return has_concat_op<It>(0); }
template <class It>
constexpr bool has_concat() {
static_assert(has_concat<It>(0) == has_concat_op<It>(0), "must be same");
return has_concat<It>(0) && has_concat_op<It>(0);
}
void test_sfinae() {
using namespace fs;
{
static_assert(has_concat_op<char>(), "");
static_assert(has_concat_op<const char>(), "");
static_assert(has_concat_op<char16_t>(), "");
static_assert(has_concat_op<const char16_t>(), "");
}
{
using It = const char* const;
static_assert(has_concat<It>(), "");
}
{
using It = input_iterator<const char*>;
static_assert(has_concat<It>(), "");
}
{
struct Traits {
using iterator_category = std::input_iterator_tag;
using value_type = const char;
using pointer = const char*;
using reference = const char&;
using difference_type = std::ptrdiff_t;
};
using It = input_iterator<const char*, Traits>;
static_assert(has_concat<It>(), "");
}
{
using It = output_iterator<const char*>;
static_assert(!has_concat<It>(), "");
}
{
static_assert(!has_concat<int>(0), "");
// operator+=(int) is well formed since it converts to operator+=(value_type)
// but concat(int) isn't valid because there is no concat(value_type).
// This should probably be addressed by a LWG issue.
static_assert(has_concat_op<int>(), "");
}
{
static_assert(!has_concat<int*>(), "");
}
}
int main(int, char**)
{
using namespace fs;
for (auto const & TC : Cases) {
{
path LHS((const char*)TC.lhs);
path RHS((const char*)TC.rhs);
path& Ref = (LHS += RHS);
assert(LHS == (const char*)TC.expect);
assert(&Ref == &LHS);
}
{
path LHS((const char*)TC.lhs);
std::string_view RHS((const char*)TC.rhs);
path& Ref = (LHS += RHS);
assert(LHS == (const char*)TC.expect);
assert(&Ref == &LHS);
}
doConcatSourceTest<char> (TC);
doConcatSourceTest<wchar_t> (TC);
doConcatSourceTest<char16_t>(TC);
doConcatSourceTest<char32_t>(TC);
}
for (auto const & TC : LongLHSCases) {
// Do path test
{
path LHS((const char*)TC.lhs);
path RHS((const char*)TC.rhs);
const char* E = TC.expect;
PathReserve(LHS, StrLen(E) + 5);
{
DisableAllocationGuard g;
path& Ref = (LHS += RHS);
assert(&Ref == &LHS);
}
assert(LHS == E);
}
{
path LHS((const char*)TC.lhs);
std::string_view RHS((const char*)TC.rhs);
const char* E = TC.expect;
PathReserve(LHS, StrLen(E) + 5);
{
DisableAllocationGuard g;
path& Ref = (LHS += RHS);
assert(&Ref == &LHS);
}
assert(LHS == E);
}
doConcatSourceAllocTest<char>(TC);
doConcatSourceAllocTest<wchar_t>(TC);
}
for (auto const& TC : CharTestCases) {
doConcatECharTest<char>(TC);
doConcatECharTest<wchar_t>(TC);
doConcatECharTest<char16_t>(TC);
doConcatECharTest<char32_t>(TC);
}
test_sfinae();
return 0;
}

View File

@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path(path const&)
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
int main(int, char**) {
using namespace fs;
static_assert(std::is_copy_constructible<path>::value, "");
static_assert(!std::is_nothrow_copy_constructible<path>::value, "should not be noexcept");
const std::string s("foo");
const path p(s);
path p2(p);
assert(p.native() == s);
assert(p2.native() == s);
return 0;
}

View File

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path() noexcept
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
int main(int, char**) {
using namespace fs;
static_assert(std::is_nothrow_default_constructible<path>::value, "");
const path p;
assert(p.empty());
return 0;
}

View File

@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path(path&&) noexcept
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "count_new.hpp"
int main(int, char**) {
using namespace fs;
static_assert(std::is_nothrow_move_constructible<path>::value, "");
assert(globalMemCounter.checkOutstandingNewEq(0));
const std::string s("we really really really really really really really "
"really really long string so that we allocate");
assert(globalMemCounter.checkOutstandingNewEq(1));
path p(s);
{
DisableAllocationGuard g;
path p2(std::move(p));
assert(p2.native() == s);
assert(p.native() != s); // Testing moved from state
}
return 0;
}

View File

@ -0,0 +1,130 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// template <class Source>
// path(const Source& source);
// template <class InputIterator>
// path(InputIterator first, InputIterator last);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "min_allocator.h"
#include "filesystem_test_helper.hpp"
template <class CharT, class ...Args>
void RunTestCaseImpl(MultiStringType const& MS, Args... args) {
using namespace fs;
const char* Expect = MS;
const CharT* TestPath = MS;
const CharT* TestPathEnd = StrEnd(TestPath);
const std::size_t Size = TestPathEnd - TestPath;
const std::size_t SSize = StrEnd(Expect) - Expect;
assert(Size == SSize);
// StringTypes
{
const std::basic_string<CharT> S(TestPath);
path p(S, args...);
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
assert(p.string<CharT>() == S);
}
{
const std::basic_string_view<CharT> S(TestPath);
path p(S, args...);
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
assert(p.string<CharT>() == S);
}
// Char* pointers
{
path p(TestPath, args...);
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
{
path p(TestPath, TestPathEnd, args...);
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
// Iterators
{
using It = input_iterator<const CharT*>;
path p(It{TestPath}, args...);
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
{
using It = input_iterator<const CharT*>;
path p(It{TestPath}, It{TestPathEnd}, args...);
assert(p.native() == Expect);
assert(p.string<CharT>() == TestPath);
}
}
template <class CharT, class ...Args>
void RunTestCase(MultiStringType const& MS) {
RunTestCaseImpl<CharT>(MS);
RunTestCaseImpl<CharT>(MS, fs::path::format::auto_format);
RunTestCaseImpl<CharT>(MS, fs::path::format::native_format);
RunTestCaseImpl<CharT>(MS, fs::path::format::generic_format);
}
void test_sfinae() {
using namespace fs;
{
using It = const char* const;
static_assert(std::is_constructible<path, It>::value, "");
}
{
using It = input_iterator<const char*>;
static_assert(std::is_constructible<path, It>::value, "");
}
{
struct Traits {
using iterator_category = std::input_iterator_tag;
using value_type = const char;
using pointer = const char*;
using reference = const char&;
using difference_type = std::ptrdiff_t;
};
using It = input_iterator<const char*, Traits>;
static_assert(std::is_constructible<path, It>::value, "");
}
{
using It = output_iterator<const char*>;
static_assert(!std::is_constructible<path, It>::value, "");
}
{
static_assert(!std::is_constructible<path, int*>::value, "");
}
}
int main(int, char**) {
for (auto const& MS : PathList) {
RunTestCase<char>(MS);
RunTestCase<wchar_t>(MS);
RunTestCase<char16_t>(MS);
RunTestCase<char32_t>(MS);
}
test_sfinae();
return 0;
}

View File

@ -0,0 +1,29 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <filesystem>
// class path
// bool empty() const noexcept;
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
// UNSUPPORTED: clang-3.3, clang-3.4, clang-3.5, clang-3.6, clang-3.7, clang-3.8
#include "filesystem_include.hpp"
#include "test_macros.h"
int main(int, char**)
{
fs::path c;
c.empty(); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}}
return 0;
}

View File

@ -0,0 +1,217 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// 8.4.9 path decomposition [path.decompose]
//------------------------------------------
// path root_name() const;
// path root_directory() const;
// path root_path() const;
// path relative_path() const;
// path parent_path() const;
// path filename() const;
// path stem() const;
// path extension() const;
//-------------------------------
// 8.4.10 path query [path.query]
//-------------------------------
// bool empty() const noexcept;
// bool has_root_path() const;
// bool has_root_name() const;
// bool has_root_directory() const;
// bool has_relative_path() const;
// bool has_parent_path() const;
// bool has_filename() const;
// bool has_stem() const;
// bool has_extension() const;
// bool is_absolute() const;
// bool is_relative() const;
//-------------------------------
// 8.5 path iterators [path.itr]
//-------------------------------
// iterator begin() const;
// iterator end() const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <vector>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
#include "assert_checkpoint.h"
#include "verbose_assert.h"
struct ComparePathExact {
bool operator()(std::string const& LHS, std::string const& RHS) const {
return LHS == RHS;
}
};
struct PathDecomposeTestcase
{
std::string raw;
std::vector<std::string> elements;
std::string root_path;
std::string root_name;
std::string root_directory;
std::string relative_path;
std::string parent_path;
std::string filename;
};
const PathDecomposeTestcase PathTestCases[] =
{
{"", {}, "", "", "", "", "", ""}
, {".", {"."}, "", "", "", ".", "", "."}
, {"..", {".."}, "", "", "", "..", "", ".."}
, {"foo", {"foo"}, "", "", "", "foo", "", "foo"}
, {"/", {"/"}, "/", "", "/", "", "/", ""}
, {"/foo", {"/", "foo"}, "/", "", "/", "foo", "/", "foo"}
, {"foo/", {"foo", ""}, "", "", "", "foo/", "foo", ""}
, {"/foo/", {"/", "foo", ""}, "/", "", "/", "foo/", "/foo", ""}
, {"foo/bar", {"foo","bar"}, "", "", "", "foo/bar", "foo", "bar"}
, {"/foo//bar", {"/","foo","bar"}, "/", "", "/", "foo/bar", "/foo", "bar"}
, {"//net", {"/", "net"}, "/", "", "/", "net", "/", "net"}
, {"//net/foo", {"/", "net", "foo"}, "/", "", "/", "net/foo", "/net", "foo"}
, {"///foo///", {"/", "foo", ""}, "/", "", "/", "foo///", "///foo", ""}
, {"///foo///bar", {"/", "foo", "bar"}, "/", "", "/", "foo///bar", "///foo", "bar"}
, {"/.", {"/", "."}, "/", "", "/", ".", "/", "."}
, {"./", {".", ""}, "", "", "", "./", ".", ""}
, {"/..", {"/", ".."}, "/", "", "/", "..", "/", ".."}
, {"../", {"..", ""}, "", "", "", "../", "..", ""}
, {"foo/.", {"foo", "."}, "", "", "", "foo/.", "foo", "."}
, {"foo/..", {"foo", ".."}, "", "", "", "foo/..", "foo", ".."}
, {"foo/./", {"foo", ".", ""}, "", "", "", "foo/./", "foo/.", ""}
, {"foo/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar", "foo/.", "bar"}
, {"foo/../", {"foo", "..", ""}, "", "", "", "foo/../", "foo/..", ""}
, {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar", "foo/..", "bar"}
, {"c:", {"c:"}, "", "", "", "c:", "", "c:"}
, {"c:/", {"c:", ""}, "", "", "", "c:/", "c:", ""}
, {"c:foo", {"c:foo"}, "", "", "", "c:foo", "", "c:foo"}
, {"c:/foo", {"c:", "foo"}, "", "", "", "c:/foo", "c:", "foo"}
, {"c:foo/", {"c:foo", ""}, "", "", "", "c:foo/", "c:foo", ""}
, {"c:/foo/", {"c:", "foo", ""}, "", "", "", "c:/foo/", "c:/foo", ""}
, {"c:/foo/bar", {"c:", "foo", "bar"}, "", "", "", "c:/foo/bar", "c:/foo", "bar"}
, {"prn:", {"prn:"}, "", "", "", "prn:", "", "prn:"}
, {"c:\\", {"c:\\"}, "", "", "", "c:\\", "", "c:\\"}
, {"c:\\foo", {"c:\\foo"}, "", "", "", "c:\\foo", "", "c:\\foo"}
, {"c:foo\\", {"c:foo\\"}, "", "", "", "c:foo\\", "", "c:foo\\"}
, {"c:\\foo\\", {"c:\\foo\\"}, "", "", "", "c:\\foo\\", "", "c:\\foo\\"}
, {"c:\\foo/", {"c:\\foo", ""}, "", "", "", "c:\\foo/", "c:\\foo", ""}
, {"c:/foo\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar", "c:", "foo\\bar"}
, {"//", {"/"}, "/", "", "/", "", "/", ""}
};
void decompPathTest()
{
using namespace fs;
for (auto const & TC : PathTestCases) {
CHECKPOINT(TC.raw.c_str());
fs::path p(TC.raw);
ASSERT(p == TC.raw);
ASSERT_EQ(p.root_path(), TC.root_path);
ASSERT_NEQ(p.has_root_path(), TC.root_path.empty());
ASSERT(p.root_name().native().empty())
<< DISPLAY(p.root_name());
ASSERT_EQ(p.root_name(),TC.root_name);
ASSERT_NEQ(p.has_root_name(), TC.root_name.empty());
ASSERT_EQ(p.root_directory(), TC.root_directory);
ASSERT_NEQ(p.has_root_directory(), TC.root_directory.empty());
ASSERT_EQ(p.relative_path(), TC.relative_path);
ASSERT_NEQ(p.has_relative_path(), TC.relative_path.empty());
ASSERT_EQ(p.parent_path(), TC.parent_path);
ASSERT_NEQ(p.has_parent_path(), TC.parent_path.empty());
ASSERT_EQ(p.filename(), TC.filename);
ASSERT_NEQ(p.has_filename(), TC.filename.empty());
ASSERT_EQ(p.is_absolute(), p.has_root_directory());
ASSERT_NEQ(p.is_relative(), p.is_absolute());
if (p.empty())
ASSERT(p.is_relative());
ASSERT_COLLECTION_EQ_COMP(
p.begin(), p.end(),
TC.elements.begin(), TC.elements.end(),
ComparePathExact()
);
// check backwards
std::vector<fs::path> Parts;
for (auto it = p.end(); it != p.begin(); )
Parts.push_back(*--it);
ASSERT_COLLECTION_EQ_COMP(Parts.begin(), Parts.end(),
TC.elements.rbegin(), TC.elements.rend(),
ComparePathExact());
}
}
struct FilenameDecompTestcase
{
std::string raw;
std::string filename;
std::string stem;
std::string extension;
};
const FilenameDecompTestcase FilenameTestCases[] =
{
{"", "", "", ""}
, {".", ".", ".", ""}
, {"..", "..", "..", ""}
, {"/", "", "", ""}
, {"foo", "foo", "foo", ""}
, {"/foo/bar.txt", "bar.txt", "bar", ".txt"}
, {"foo..txt", "foo..txt", "foo.", ".txt"}
, {".profile", ".profile", ".profile", ""}
, {".profile.txt", ".profile.txt", ".profile", ".txt"}
};
void decompFilenameTest()
{
using namespace fs;
for (auto const & TC : FilenameTestCases) {
CHECKPOINT(TC.raw.c_str());
fs::path p(TC.raw);
ASSERT_EQ(p, TC.raw);
ASSERT_NOEXCEPT(p.empty());
ASSERT_EQ(p.filename(), TC.filename);
ASSERT_NEQ(p.has_filename(), TC.filename.empty());
ASSERT_EQ(p.stem(), TC.stem);
ASSERT_NEQ(p.has_stem(), TC.stem.empty());
ASSERT_EQ(p.extension(), TC.extension);
ASSERT_NEQ(p.has_extension(), TC.extension.empty());
}
}
int main(int, char**)
{
decompPathTest();
decompFilenameTest();
return 0;
}

View File

@ -0,0 +1,141 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path lexically_normal() const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <vector>
#include <iostream>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
int main(int, char**) {
// clang-format off
struct {
std::string input;
std::string expect;
} TestCases[] = {
{"", ""},
{"/a/b/c", "/a/b/c"},
{"/a/b//c", "/a/b/c"},
{"foo/./bar/..", "foo/"},
{"foo/.///bar/../", "foo/"},
{"/a/b/", "/a/b/"},
{"a/b", "a/b"},
{"a/b/.", "a/b/"},
{"a/b/./", "a/b/"},
{"a/..", "."},
{".", "."},
{"./", "."},
{"./.", "."},
{"./..", ".."},
{"..", ".."},
{"../..", "../.."},
{"/../", "/"},
{"/../..", "/"},
{"/../../", "/"},
{"..", ".."},
{"../", ".."},
{"/a/b/c/../", "/a/b/"},
{"/a/b/./", "/a/b/"},
{"/a/b/c/../d", "/a/b/d"},
{"/a/b/c/../d/", "/a/b/d/"},
{"//a/", "/a/"},
{"//a/b/", "/a/b/"},
{"//a/b/.", "/a/b/"},
{"//a/..", "/"},
///===---------------------------------------------------------------===//
/// Tests specifically for the clauses under [fs.path.generic]p6
///===---------------------------------------------------------------===//
// p1: If the path is empty, stop.
{"", ""},
// p2: Replace each slash character in the root-name with a preferred
// separator.
{"NO_ROOT_NAME_ON_LINUX", "NO_ROOT_NAME_ON_LINUX"},
// p3: Replace each directory-separator with a preferred-separator.
// [Note: The generic pathname grammar ([fs.path.generic]) defines
// directory-separator as one or more slashes and preferred-separators.
// —end note]
{"/", "/"},
{"//", "/"},
{"///", "/"},
{"a/b", "a/b"},
{"a//b", "a/b"},
{"a///b", "a/b"},
{"a/b/", "a/b/"},
{"a/b//", "a/b/"},
{"a/b///", "a/b/"},
{"///a////b//////", "/a/b/"},
// p4: Remove each dot filename and any immediately following directory
// separators
{"foo/.", "foo/"},
{"foo/./bar/.", "foo/bar/"},
{"./foo/././bar/./", "foo/bar/"},
{".///foo//.////./bar/.///", "foo/bar/"},
// p5: As long as any appear, remove a non-dot-dot filename immediately
// followed by a directory-separator and a dot-dot filename, along with
// any immediately following directory separator.
{"foo/..", "."},
{"foo/../", "."},
{"foo/bar/..", "foo/"},
{"foo/bar/../", "foo/"},
{"foo/bar/../..", "."},
{"foo/bar/../../", "."},
{"foo/bar/baz/../..", "foo/"},
{"foo/bar/baz/../../", "foo/"},
{"foo/bar/./..", "foo/"},
{"foo/bar/./../", "foo/"},
// p6: If there is a root-directory, remove all dot-dot filenames and any
// directory-separators immediately following them. [Note: These dot-dot
// filenames attempt to refer to nonexistent parent directories. —end note]
{"/..", "/"},
{"/../", "/"},
{"/foo/../..", "/"},
{"/../foo", "/foo"},
{"/../foo/../..", "/"},
// p7: If the last filename is dot-dot, remove any trailing
// directory-separator.
{"../", ".."},
{"../../", "../.."},
{"foo/../bar/../..///", ".."},
{"foo/../bar/..//..///../", "../.."},
// p8: If the path is empty, add a dot
{".", "."},
{"./", "."},
{"foo/..", "."}
};
// clang-format on
int ID = 0;
bool Failed = false;
for (auto& TC : TestCases) {
++ID;
fs::path p(TC.input);
const fs::path output = p.lexically_normal();
if (!PathEq(output, TC.expect)) {
Failed = true;
std::cerr << "TEST CASE #" << ID << " FAILED: \n";
std::cerr << " Input: '" << TC.input << "'\n";
std::cerr << " Expected: '" << TC.expect << "'\n";
std::cerr << " Output: '" << output.native() << "'";
std::cerr << std::endl;
}
}
return Failed;
}

View File

@ -0,0 +1,88 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path lexically_relative(const path& p) const;
// path lexically_proximate(const path& p) const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <vector>
#include <iostream>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
int main(int, char**) {
// clang-format off
struct {
std::string input;
std::string base;
std::string expect;
} TestCases[] = {
{"", "", "."},
{"/", "a", ""},
{"a", "/", ""},
{"//net", "a", ""},
{"a", "//net", ""},
{"//net/", "//net", "."},
{"//net", "//net/", "."},
{"//base", "a", ""},
{"a", "a", "."},
{"a/b", "a/b", "."},
{"a/b/c/", "a/b/c/", "."},
{"//net", "//net", "."},
{"//net/", "//net/", "."},
{"//net/a/b", "//net/a/b", "."},
{"/a/d", "/a/b/c", "../../d"},
{"/a/b/c", "/a/d", "../b/c"},
{"a/b/c", "a", "b/c"},
{"a/b/c", "a/b/c/x/y", "../.."},
{"a/b/c", "a/b/c", "."},
{"a/b", "c/d", "../../a/b"}
};
// clang-format on
int ID = 0;
bool Failed = false;
for (auto& TC : TestCases) {
++ID;
const fs::path p(TC.input);
const fs::path output = p.lexically_relative(TC.base);
auto ReportErr = [&](const char* Testing, fs::path const& Output,
fs::path const& Expected) {
Failed = true;
std::cerr << "TEST CASE #" << ID << " FAILED: \n";
std::cerr << " Testing: " << Testing << "\n";
std::cerr << " Input: '" << TC.input << "'\n";
std::cerr << " Base: '" << TC.base << "'\n";
std::cerr << " Expected: '" << Expected << "'\n";
std::cerr << " Output: '" << Output.native() << "'";
std::cerr << std::endl;
};
if (!PathEq(output, TC.expect))
ReportErr("path::lexically_relative", output, TC.expect);
const fs::path proximate_output = p.lexically_proximate(TC.base);
// [path.gen] lexically_proximate
// Returns: If the value of lexically_relative(base) is not an empty path,
// return it.Otherwise return *this.
const fs::path proximate_expected = output.native().empty() ? p
: output;
if (!PathEq(proximate_expected, proximate_output))
ReportErr("path::lexically_proximate", proximate_output, proximate_expected);
}
return Failed;
}

View File

@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// template <class ECharT, class Traits = char_traits<ECharT>,
// class Allocator = allocator<ECharT>>
// basic_string<ECharT, Traits, Allocator>
// generic_string(const Allocator& a = Allocator()) const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "min_allocator.h"
#include "filesystem_test_helper.hpp"
MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
// generic_string<C, T, A> forwards to string<C, T, A>. Tests for
// string<C, T, A>() are in "path.native.op/string_alloc.pass.cpp".
// generic_string is minimally tested here.
int main(int, char**)
{
using namespace fs;
using CharT = wchar_t;
using Traits = std::char_traits<CharT>;
using Alloc = malloc_allocator<CharT>;
using Str = std::basic_string<CharT, Traits, Alloc>;
const wchar_t* expect = longString;
const path p((const char*)longString);
{
DisableAllocationGuard g;
Alloc a;
Alloc::disable_default_constructor = true;
Str s = p.generic_string<wchar_t, Traits, Alloc>(a);
assert(s == expect);
assert(Alloc::alloc_count > 0);
assert(Alloc::outstanding_alloc() == 1);
}
return 0;
}

View File

@ -0,0 +1,62 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// std::string generic_string() const;
// std::wstring generic_wstring() const;
// std::u8string generic_u8string() const;
// std::u16string generic_u16string() const;
// std::u32string generic_u32string() const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "min_allocator.h"
#include "filesystem_test_helper.hpp"
MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
int main(int, char**)
{
using namespace fs;
auto const& MS = longString;
const char* value = longString;
const path p(value);
{
std::string s = p.generic_string();
assert(s == value);
}
{
std::string s = p.generic_u8string();
assert(s == (const char*)MS);
}
{
std::wstring s = p.generic_wstring();
assert(s == (const wchar_t*)MS);
}
{
std::u16string s = p.generic_u16string();
assert(s == (const char16_t*)MS);
}
{
std::u32string s = p.generic_u32string();
assert(s == (const char32_t*)MS);
}
return 0;
}

View File

@ -0,0 +1,45 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// void clear() noexcept
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
int main(int, char**) {
using namespace fs;
{
path p;
ASSERT_NOEXCEPT(p.clear());
ASSERT_SAME_TYPE(void, decltype(p.clear()));
p.clear();
assert(p.empty());
}
{
const path p("/foo/bar/baz");
path p2(p);
assert(p == p2);
p2.clear();
assert(p2.empty());
}
return 0;
}

View File

@ -0,0 +1,55 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& make_preferred()
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
struct MakePreferredTestcase {
const char* value;
};
const MakePreferredTestcase TestCases[] =
{
{""}
, {"hello_world"}
, {"/"}
, {"/foo/bar/baz/"}
, {"\\"}
, {"\\foo\\bar\\baz\\"}
, {"\\foo\\/bar\\/baz\\"}
};
int main(int, char**)
{
// This operation is an identity operation on linux.
using namespace fs;
for (auto const & TC : TestCases) {
path p(TC.value);
assert(p == TC.value);
path& Ref = (p.make_preferred());
assert(p.native() == TC.value);
assert(&Ref == &p);
}
return 0;
}

View File

@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& remove_filename()
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
#include "verbose_assert.h"
struct RemoveFilenameTestcase {
const char* value;
const char* expect;
};
const RemoveFilenameTestcase TestCases[] =
{
{"", ""}
, {"/", "/"}
, {"//", "//"}
, {"///", "///"}
, {"\\", ""}
, {".", ""}
, {"..", ""}
, {"/foo", "/"}
, {"foo/bar", "foo/"}
, {"foo/", "foo/"}
, {"//foo", "//"}
, {"//foo/", "//foo/"}
, {"//foo///", "//foo///"}
, {"///foo", "///"}
, {"///foo/", "///foo/"}
, {"/foo/", "/foo/"}
, {"/foo/.", "/foo/"}
, {"/foo/..", "/foo/"}
, {"/foo/////", "/foo/////"}
, {"/foo\\\\", "/"}
, {"/foo//\\/", "/foo//\\/"}
, {"///foo", "///"}
, {"file.txt", ""}
, {"bar/../baz/./file.txt", "bar/../baz/./"}
};
int main(int, char**)
{
using namespace fs;
for (auto const & TC : TestCases) {
path const p_orig(TC.value);
path p(p_orig);
assert(p == TC.value);
path& Ref = (p.remove_filename());
ASSERT_EQ(p, TC.expect) << DISPLAY(p_orig);
assert(&Ref == &p);
assert(!p.has_filename());
}
return 0;
}

View File

@ -0,0 +1,73 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& replace_extension(path const& p = path())
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
struct ReplaceExtensionTestcase {
const char* value;
const char* expect;
const char* extension;
};
const ReplaceExtensionTestcase TestCases[] =
{
{"", "", ""}
, {"foo.cpp", "foo", ""}
, {"foo.cpp", "foo.", "."}
, {"foo..cpp", "foo..txt", "txt"}
, {"", ".txt", "txt"}
, {"", ".txt", ".txt"}
, {"/foo", "/foo.txt", ".txt"}
, {"/foo", "/foo.txt", "txt"}
, {"/foo.cpp", "/foo.txt", ".txt"}
, {"/foo.cpp", "/foo.txt", "txt"}
};
const ReplaceExtensionTestcase NoArgCases[] =
{
{"", "", ""}
, {"foo", "foo", ""}
, {"foo.cpp", "foo", ""}
, {"foo..cpp", "foo.", ""}
};
int main(int, char**)
{
using namespace fs;
for (auto const & TC : TestCases) {
path p(TC.value);
assert(p == TC.value);
path& Ref = (p.replace_extension(TC.extension));
assert(p == TC.expect);
assert(&Ref == &p);
}
for (auto const& TC : NoArgCases) {
path p(TC.value);
assert(p == TC.value);
path& Ref = (p.replace_extension());
assert(p == TC.expect);
assert(&Ref == &p);
}
return 0;
}

View File

@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// path& replace_filename()
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
#include "assert_checkpoint.h"
#include "verbose_assert.h"
struct ReplaceFilenameTestcase {
const char* value;
const char* expect;
const char* filename;
};
const ReplaceFilenameTestcase TestCases[] =
{
{"/foo", "/bar", "bar"}
, {"/foo", "/", ""}
, {"foo", "bar", "bar"}
, {"/", "/bar", "bar"}
, {"\\", "bar", "bar"}
, {"///", "///bar", "bar"}
, {"\\\\", "bar", "bar"}
, {"\\/\\", "\\/bar", "bar"}
, {".", "bar", "bar"}
, {"..", "bar", "bar"}
, {"/foo\\baz/bong/", "/foo\\baz/bong/bar", "bar"}
, {"/foo\\baz/bong", "/foo\\baz/bar", "bar"}
};
int main(int, char**)
{
using namespace fs;
for (auto const & TC : TestCases) {
path p(TC.value);
ASSERT_EQ(p, TC.value);
path& Ref = (p.replace_filename(TC.filename));
ASSERT_EQ(p, TC.expect)
<< DISPLAY(TC.value)
<< DISPLAY(TC.filename);
assert(&Ref == &p);
// Tests Effects "as-if": remove_filename() append(filename)
{
path p2(TC.value);
path replace(TC.filename);
p2.remove_filename();
p2 /= replace;
ASSERT_EQ(p, p2);
}
}
return 0;
}

View File

@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// void swap(path& rhs) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
struct SwapTestcase {
const char* value1;
const char* value2;
};
#define LONG_STR1 "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG"
#define LONG_STR2 "_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2"
const SwapTestcase TestCases[] =
{
{"", ""}
, {"shortstr", LONG_STR1}
, {LONG_STR1, "shortstr"}
, {LONG_STR1, LONG_STR2}
};
#undef LONG_STR1
#undef LONG_STR2
int main(int, char**)
{
using namespace fs;
{
path p;
ASSERT_NOEXCEPT(p.swap(p));
ASSERT_SAME_TYPE(void, decltype(p.swap(p)));
}
for (auto const & TC : TestCases) {
path p1(TC.value1);
path p2(TC.value2);
{
DisableAllocationGuard g;
p1.swap(p2);
}
assert(p1 == TC.value2);
assert(p2 == TC.value1);
{
DisableAllocationGuard g;
p1.swap(p2);
}
assert(p1 == TC.value1);
assert(p2 == TC.value2);
}
// self-swap
{
const char* Val = "aoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeu";
path p1(Val);
assert(p1 == Val);
{
DisableAllocationGuard g;
p1.swap(p1);
}
assert(p1 == Val);
}
return 0;
}

View File

@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// const value_type* c_str() const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "filesystem_test_helper.hpp"
int main(int, char**)
{
using namespace fs;
const char* const value = "hello world";
const std::string str_value = value;
{ // Check signature
path p(value);
ASSERT_SAME_TYPE(path::value_type const*, decltype(p.c_str()));
ASSERT_NOEXCEPT(p.c_str());
}
{
path p(value);
assert(p.c_str() == str_value);
assert(p.native().c_str() == p.c_str());
}
return 0;
}

View File

@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// std::string string() const;
// std::wstring wstring() const;
// std::u8string u8string() const;
// std::u16string u16string() const;
// std::u32string u32string() const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "min_allocator.h"
#include "filesystem_test_helper.hpp"
MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
int main(int, char**)
{
using namespace fs;
auto const& MS = longString;
const char* value = longString;
const path p(value);
{
std::string s = p.string();
assert(s == value);
}
{
std::string s = p.u8string();
assert(s == (const char*)MS);
}
{
std::wstring s = p.wstring();
assert(s == (const wchar_t*)MS);
}
{
std::u16string s = p.u16string();
assert(s == (const char16_t*)MS);
}
{
std::u32string s = p.u32string();
assert(s == (const char32_t*)MS);
}
return 0;
}

View File

@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// const string_type& native() const noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "filesystem_test_helper.hpp"
int main(int, char**)
{
using namespace fs;
const char* const value = "hello world";
{ // Check signature
path p(value);
ASSERT_SAME_TYPE(path::string_type const&, decltype(p.native()));
ASSERT_NOEXCEPT(p.native());
}
{ // native() is tested elsewhere
path p(value);
assert(p.native() == value);
}
return 0;
}

View File

@ -0,0 +1,47 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// operator string_type() const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "filesystem_test_helper.hpp"
int main(int, char**)
{
using namespace fs;
using string_type = path::string_type;
const char* const value = "hello world";
{ // Check signature
path p(value);
static_assert(std::is_convertible<path, string_type>::value, "");
static_assert(std::is_constructible<string_type, path>::value, "");
ASSERT_SAME_TYPE(string_type, decltype(p.operator string_type()));
ASSERT_NOT_NOEXCEPT(p.operator string_type());
}
{
path p(value);
assert(p.native() == value);
string_type s = p;
assert(s == value);
assert(p == value);
}
return 0;
}

View File

@ -0,0 +1,138 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// template <class ECharT, class Traits = char_traits<ECharT>,
// class Allocator = allocator<ECharT>>
// basic_string<ECharT, Traits, Allocator>
// string(const Allocator& a = Allocator()) const;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "min_allocator.h"
#include "filesystem_test_helper.hpp"
// the SSO is always triggered for strings of size 2.
MultiStringType shortString = MKSTR("a");
MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
template <class CharT>
void doShortStringTest(MultiStringType const& MS) {
using namespace fs;
using Ptr = CharT const*;
using Str = std::basic_string<CharT>;
using Alloc = std::allocator<CharT>;
Ptr value = MS;
const path p((const char*)MS);
{
DisableAllocationGuard g;
Str s = p.string<CharT>();
assert(s == value);
Str s2 = p.string<CharT>(Alloc{});
assert(s2 == value);
}
using MAlloc = malloc_allocator<CharT>;
MAlloc::reset();
{
using Traits = std::char_traits<CharT>;
using AStr = std::basic_string<CharT, Traits, MAlloc>;
DisableAllocationGuard g;
AStr s = p.string<CharT, Traits, MAlloc>();
assert(s == value);
assert(MAlloc::alloc_count == 0);
assert(MAlloc::outstanding_alloc() == 0);
}
MAlloc::reset();
{ // Other allocator - provided copy
using Traits = std::char_traits<CharT>;
using AStr = std::basic_string<CharT, Traits, MAlloc>;
DisableAllocationGuard g;
MAlloc a;
// don't allow another allocator to be default constructed.
MAlloc::disable_default_constructor = true;
AStr s = p.string<CharT, Traits, MAlloc>(a);
assert(s == value);
assert(MAlloc::alloc_count == 0);
assert(MAlloc::outstanding_alloc() == 0);
}
MAlloc::reset();
}
template <class CharT>
void doLongStringTest(MultiStringType const& MS) {
using namespace fs;
using Ptr = CharT const*;
using Str = std::basic_string<CharT>;
Ptr value = MS;
const path p((const char*)MS);
{ // Default allocator
using Alloc = std::allocator<CharT>;
Str s = p.string<CharT>();
assert(s == value);
Str s2 = p.string<CharT>(Alloc{});
assert(s2 == value);
}
using MAlloc = malloc_allocator<CharT>;
MAlloc::reset();
{ // Other allocator - default construct
using Traits = std::char_traits<CharT>;
using AStr = std::basic_string<CharT, Traits, MAlloc>;
DisableAllocationGuard g;
AStr s = p.string<CharT, Traits, MAlloc>();
assert(s == value);
assert(MAlloc::alloc_count > 0);
assert(MAlloc::outstanding_alloc() == 1);
}
MAlloc::reset();
{ // Other allocator - provided copy
using Traits = std::char_traits<CharT>;
using AStr = std::basic_string<CharT, Traits, MAlloc>;
DisableAllocationGuard g;
MAlloc a;
// don't allow another allocator to be default constructed.
MAlloc::disable_default_constructor = true;
AStr s = p.string<CharT, Traits, MAlloc>(a);
assert(s == value);
assert(MAlloc::alloc_count > 0);
assert(MAlloc::outstanding_alloc() == 1);
}
MAlloc::reset();
/////////////////////////////////////////////////////////////////////////////
}
int main(int, char**)
{
using namespace fs;
{
auto const& S = shortString;
doShortStringTest<char>(S);
doShortStringTest<wchar_t>(S);
doShortStringTest<char16_t>(S);
doShortStringTest<char32_t>(S);
}
{
auto const& S = longString;
doLongStringTest<char>(S);
doLongStringTest<wchar_t>(S);
doLongStringTest<char16_t>(S);
doLongStringTest<char32_t>(S);
}
return 0;
}

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
//-------------------------------
// 8.4.10 path query [path.query]
//-------------------------------
// bool empty() const noexcept;
// bool has_root_path() const;
// bool has_root_name() const;
// bool has_root_directory() const;
// bool has_relative_path() const;
// bool has_parent_path() const;
// bool has_filename() const;
// bool has_stem() const;
// bool has_extension() const;
// bool is_absolute() const;
// bool is_relative() const;
// tested in path.decompose
int main(int, char**) {
return 0;
}

View File

@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
#include "filesystem_include.hpp"
using namespace fs;
struct ConvToPath {
operator fs::path() const {
return "";
}
};
int main(int, char**) {
ConvToPath LHS, RHS;
(void)(LHS / RHS); // expected-error {{invalid operands to binary expression}}
return 0;
}

View File

@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// path operator/(path const&, path const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "filesystem_test_helper.hpp"
// This is mainly tested via the member append functions.
int main(int, char**)
{
using namespace fs;
path p1("abc");
path p2("def");
path p3 = p1 / p2;
assert(p3 == "abc/def");
path p4 = p1 / "def";
assert(p4 == "abc/def");
return 0;
}

View File

@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
#include "filesystem_include.hpp"
using namespace fs;
struct ConvToPath {
operator fs::path() const {
return "";
}
};
int main(int, char**) {
ConvToPath LHS, RHS;
(void)(LHS == RHS); // expected-error {{invalid operands to binary expression}}
(void)(LHS != RHS); // expected-error {{invalid operands to binary expression}}
(void)(LHS < RHS); // expected-error {{invalid operands to binary expression}}
(void)(LHS <= RHS); // expected-error {{invalid operands to binary expression}}
(void)(LHS > RHS); // expected-error {{invalid operands to binary expression}}
(void)(LHS >= RHS); // expected-error {{invalid operands to binary expression}}
return 0;
}

View File

@ -0,0 +1,15 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// The comparison operators are tested as part of [path.compare]
// in class.path/path.members/path.compare.pass.cpp
int main(int, char**) {
return 0;
}

View File

@ -0,0 +1,15 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// The "hash_value" function is tested as part of [path.compare]
// in class.path/path.members/path.compare.pass.cpp
int main(int, char**) {
return 0;
}

View File

@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// template <class Source>
// path u8path(Source const&);
// template <class InputIter>
// path u8path(InputIter, InputIter);
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
int main(int, char**)
{
using namespace fs;
const char* In1 = "abcd/efg";
const std::string In2(In1);
const auto In3 = In2.begin();
const auto In3End = In2.end();
{
path p = fs::u8path(In1);
assert(p == In1);
}
{
path p = fs::u8path(In2);
assert(p == In1);
}
{
path p = fs::u8path(In3);
assert(p == In1);
}
{
path p = fs::u8path(In3, In3End);
assert(p == In1);
}
return 0;
}

View File

@ -0,0 +1,99 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// template <class charT, class traits>
// basic_ostream<charT, traits>&
// operator<<(basic_ostream<charT, traits>& os, const path& p);
//
// template <class charT, class traits>
// basic_istream<charT, traits>&
// operator>>(basic_istream<charT, traits>& is, path& p)
//
#include "filesystem_include.hpp"
#include <type_traits>
#include <sstream>
#include <cassert>
#include <iostream>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
template <class CharT>
void doIOTest() {
using namespace fs;
using Ptr = const CharT*;
using StrStream = std::basic_stringstream<CharT>;
const Ptr E = OutStr;
const path p((const char*)InStr);
StrStream ss;
{ // test output
auto& ret = (ss << p);
assert(ss.str() == E);
assert(&ret == &ss);
}
{ // test input
path p_in;
auto& ret = ss >> p_in;
assert(p_in.native() == (const char*)InStr);
assert(&ret == &ss);
}
}
namespace impl {
using namespace fs;
template <class Stream, class Tp, class = decltype(std::declval<Stream&>() << std::declval<Tp&>())>
std::true_type is_ostreamable_imp(int);
template <class Stream, class Tp>
std::false_type is_ostreamable_imp(long);
template <class Stream, class Tp, class = decltype(std::declval<Stream&>() >> std::declval<Tp&>())>
std::true_type is_istreamable_imp(int);
template <class Stream, class Tp>
std::false_type is_istreamable_imp(long);
} // namespace impl
template <class Stream, class Tp>
struct is_ostreamable : decltype(impl::is_ostreamable_imp<Stream, Tp>(0)) {};
template <class Stream, class Tp>
struct is_istreamable : decltype(impl::is_istreamable_imp<Stream, Tp>(0)) {};
void test_LWG2989() {
static_assert(!is_ostreamable<decltype(std::cout), std::wstring>::value, "");
static_assert(!is_ostreamable<decltype(std::wcout), std::string>::value, "");
static_assert(!is_istreamable<decltype(std::cin), std::wstring>::value, "");
static_assert(!is_istreamable<decltype(std::wcin), std::string>::value, "");
}
int main(int, char**) {
doIOTest<char>();
doIOTest<wchar_t>();
//doIOTest<char16_t>();
//doIOTest<char32_t>();
test_LWG2989();
return 0;
}

View File

@ -0,0 +1,70 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// template <class charT, class traits>
// basic_ostream<charT, traits>&
// operator<<(basic_ostream<charT, traits>& os, const path& p);
//
// template <class charT, class traits>
// basic_istream<charT, traits>&
// operator>>(basic_istream<charT, traits>& is, path& p)
//
// TODO(EricWF) This test fails because "std::quoted" fails to compile
// for char16_t and char32_t types. Combine with path.io.pass.cpp when this
// passes.
// XFAIL: *
#include "filesystem_include.hpp"
#include <type_traits>
#include <sstream>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
template <class CharT>
void doIOTest() {
using namespace fs;
using Ptr = const CharT*;
using StrStream = std::basic_stringstream<CharT>;
const char* const InCStr = InStr;
const Ptr E = OutStr;
const path p((const char*)InStr);
StrStream ss;
{ // test output
auto& ret = (ss << p);
assert(ss.str() == E);
assert(&ret == &ss);
}
{ // test input
path p_in;
auto& ret = ss >> p_in;
assert(p_in.native() == (const char*)InStr);
assert(&ret == &ss);
}
}
int main(int, char**) {
doIOTest<char16_t>();
doIOTest<char32_t>();
return 0;
}

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// void swap(path& lhs, path& rhs) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "count_new.hpp"
#include "filesystem_test_helper.hpp"
// NOTE: this is tested in path.members/path.modifiers via the member swap.
int main(int, char**)
{
using namespace fs;
const char* value1 = "foo/bar/baz";
const char* value2 = "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG";
path p1(value1);
path p2(value2);
{
using namespace std; using namespace fs;
ASSERT_NOEXCEPT(swap(p1, p2));
ASSERT_SAME_TYPE(void, decltype(swap(p1, p2)));
}
{
DisableAllocationGuard g;
using namespace std;
using namespace fs;
swap(p1, p2);
assert(p1.native() == value2);
assert(p2.native() == value1);
swap(p1, p2);
assert(p1.native() == value1);
assert(p2.native() == value2);
}
return 0;
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class path
// typedef ... value_type;
// typedef basic_string<value_type> string_type;
// static constexpr value_type preferred_separator = ...;
#include "filesystem_include.hpp"
#include <type_traits>
#include <cassert>
#include "test_macros.h"
int main(int, char**) {
using namespace fs;
ASSERT_SAME_TYPE(path::value_type, char);
ASSERT_SAME_TYPE(path::string_type, std::basic_string<path::value_type>);
{
ASSERT_SAME_TYPE(const path::value_type, decltype(path::preferred_separator));
static_assert(path::preferred_separator == '/', "");
// Make preferred_separator ODR used by taking its address.
const char* dummy = &path::preferred_separator;
((void)dummy);
}
return 0;
}

View File

@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class recursive_directory_iterator
// recursive_recursive_directory_iterator(recursive_recursive_directory_iterator const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(recursive_directory_iterator_copy_construct_tests)
TEST_CASE(test_constructor_signature)
{
using D = recursive_directory_iterator;
static_assert(std::is_copy_constructible<D>::value, "");
//static_assert(!std::is_nothrow_copy_constructible<D>::value, "");
}
TEST_CASE(test_copy_end_iterator)
{
const recursive_directory_iterator endIt;
recursive_directory_iterator it(endIt);
TEST_CHECK(it == endIt);
}
TEST_CASE(test_copy_valid_iterator)
{
const path testDir = StaticEnv::Dir;
const recursive_directory_iterator endIt{};
// build 'it' up with "interesting" non-default state so we can test
// that it gets copied. We want to get 'it' into a state such that:
// it.options() != directory_options::none
// it.depth() != 0
// it.recursion_pending() != true
const directory_options opts = directory_options::skip_permission_denied;
recursive_directory_iterator it(testDir, opts);
TEST_REQUIRE(it != endIt);
while (it.depth() == 0) {
++it;
TEST_REQUIRE(it != endIt);
}
it.disable_recursion_pending();
TEST_CHECK(it.options() == opts);
TEST_CHECK(it.depth() == 1);
TEST_CHECK(it.recursion_pending() == false);
const path entry = *it;
// OPERATION UNDER TEST //
const recursive_directory_iterator it2(it);
// ------------------- //
TEST_REQUIRE(it2 == it);
TEST_CHECK(*it2 == entry);
TEST_CHECK(it2.depth() == 1);
TEST_CHECK(it2.recursion_pending() == false);
TEST_CHECK(it != endIt);
}
TEST_SUITE_END()

View File

@ -0,0 +1,157 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class recursive_directory_iterator
// recursive_directory_iterator& operator=(recursive_directory_iterator const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(recursive_directory_iterator_copy_assign_tests)
recursive_directory_iterator createInterestingIterator()
// Create an "interesting" iterator where all fields are
// in a non-default state. The returned 'it' is in a
// state such that:
// it.options() == directory_options::skip_permission_denied
// it.depth() == 1
// it.recursion_pending() == true
{
const path testDir = StaticEnv::Dir;
const recursive_directory_iterator endIt;
recursive_directory_iterator it(testDir,
directory_options::skip_permission_denied);
TEST_ASSERT(it != endIt);
while (it.depth() != 1) {
++it;
TEST_ASSERT(it != endIt);
}
TEST_ASSERT(it.depth() == 1);
it.disable_recursion_pending();
return it;
}
recursive_directory_iterator createDifferentInterestingIterator()
// Create an "interesting" iterator where all fields are
// in a non-default state. The returned 'it' is in a
// state such that:
// it.options() == directory_options::follow_directory_symlink
// it.depth() == 2
// it.recursion_pending() == false
{
const path testDir = StaticEnv::Dir;
const recursive_directory_iterator endIt;
recursive_directory_iterator it(testDir,
directory_options::follow_directory_symlink);
TEST_ASSERT(it != endIt);
while (it.depth() != 2) {
++it;
TEST_ASSERT(it != endIt);
}
TEST_ASSERT(it.depth() == 2);
return it;
}
TEST_CASE(test_assignment_signature) {
using D = recursive_directory_iterator;
static_assert(std::is_copy_assignable<D>::value, "");
}
TEST_CASE(test_copy_to_end_iterator)
{
const recursive_directory_iterator endIt;
const recursive_directory_iterator from = createInterestingIterator();
const path entry = *from;
recursive_directory_iterator to;
to = from;
TEST_REQUIRE(to == from);
TEST_CHECK(*to == entry);
TEST_CHECK(to.options() == from.options());
TEST_CHECK(to.depth() == from.depth());
TEST_CHECK(to.recursion_pending() == from.recursion_pending());
}
TEST_CASE(test_copy_from_end_iterator)
{
const recursive_directory_iterator from;
recursive_directory_iterator to = createInterestingIterator();
to = from;
TEST_REQUIRE(to == from);
TEST_CHECK(to == recursive_directory_iterator{});
}
TEST_CASE(test_copy_valid_iterator)
{
const recursive_directory_iterator endIt;
const recursive_directory_iterator it = createInterestingIterator();
const path entry = *it;
recursive_directory_iterator it2 = createDifferentInterestingIterator();
TEST_REQUIRE(it2 != it);
TEST_CHECK(it2.options() != it.options());
TEST_CHECK(it2.depth() != it.depth());
TEST_CHECK(it2.recursion_pending() != it.recursion_pending());
TEST_CHECK(*it2 != entry);
it2 = it;
TEST_REQUIRE(it2 == it);
TEST_CHECK(it2.options() == it.options());
TEST_CHECK(it2.depth() == it.depth());
TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
TEST_CHECK(*it2 == entry);
}
TEST_CASE(test_returns_reference_to_self)
{
const recursive_directory_iterator it;
recursive_directory_iterator it2;
recursive_directory_iterator& ref = (it2 = it);
TEST_CHECK(&ref == &it2);
}
TEST_CASE(test_self_copy)
{
// Create two non-equal iterators that have exactly the same state.
recursive_directory_iterator it = createInterestingIterator();
recursive_directory_iterator it2 = createInterestingIterator();
TEST_CHECK(it != it2);
TEST_CHECK(it2.options() == it.options());
TEST_CHECK(it2.depth() == it.depth());
TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
TEST_CHECK(*it2 == *it);
// perform a self-copy and check that the state still matches the
// other unmodified iterator.
recursive_directory_iterator const& cit = it;
it = cit;
TEST_CHECK(it2.options() == it.options());
TEST_CHECK(it2.depth() == it.depth());
TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
TEST_CHECK(*it2 == *it);
}
TEST_SUITE_END()

View File

@ -0,0 +1,245 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class directory_iterator
//
// explicit recursive_directory_iterator(const path& p);
// recursive_directory_iterator(const path& p, directory_options options);
// recursive_directory_iterator(const path& p, error_code& ec);
// recursive_directory_iterator(const path& p, directory_options options, error_code& ec);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
using RDI = recursive_directory_iterator;
TEST_SUITE(recursive_directory_iterator_constructor_tests)
TEST_CASE(test_constructor_signatures)
{
using D = recursive_directory_iterator;
// explicit directory_iterator(path const&);
static_assert(!std::is_convertible<path, D>::value, "");
static_assert(std::is_constructible<D, path>::value, "");
static_assert(!std::is_nothrow_constructible<D, path>::value, "");
// directory_iterator(path const&, error_code&)
static_assert(std::is_constructible<D, path,
std::error_code&>::value, "");
static_assert(!std::is_nothrow_constructible<D, path,
std::error_code&>::value, "");
// directory_iterator(path const&, directory_options);
static_assert(std::is_constructible<D, path, directory_options>::value, "");
static_assert(!std::is_nothrow_constructible<D, path, directory_options>::value, "");
// directory_iterator(path const&, directory_options, error_code&)
static_assert(std::is_constructible<D, path, directory_options, std::error_code&>::value, "");
static_assert(!std::is_nothrow_constructible<D, path, directory_options, std::error_code&>::value, "");
}
TEST_CASE(test_construction_from_bad_path)
{
std::error_code ec;
directory_options opts = directory_options::none;
const RDI endIt;
const path testPaths[] = { StaticEnv::DNE, StaticEnv::BadSymlink };
for (path const& testPath : testPaths)
{
{
RDI it(testPath, ec);
TEST_CHECK(ec);
TEST_CHECK(it == endIt);
}
{
RDI it(testPath, opts, ec);
TEST_CHECK(ec);
TEST_CHECK(it == endIt);
}
{
TEST_CHECK_THROW(filesystem_error, RDI(testPath));
TEST_CHECK_THROW(filesystem_error, RDI(testPath, opts));
}
}
}
TEST_CASE(access_denied_test_case)
{
using namespace fs;
scoped_test_env env;
path const testDir = env.make_env_path("dir1");
path const testFile = testDir / "testFile";
env.create_dir(testDir);
env.create_file(testFile, 42);
// Test that we can iterator over the directory before changing the perms
{
RDI it(testDir);
TEST_REQUIRE(it != RDI{});
}
// Change the permissions so we can no longer iterate
permissions(testDir, perms::none);
// Check that the construction fails when skip_permissions_denied is
// not given.
{
std::error_code ec;
RDI it(testDir, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == RDI{});
}
// Check that construction does not report an error when
// 'skip_permissions_denied' is given.
{
std::error_code ec;
RDI it(testDir, directory_options::skip_permission_denied, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it == RDI{});
}
}
TEST_CASE(access_denied_to_file_test_case)
{
using namespace fs;
scoped_test_env env;
path const testFile = env.make_env_path("file1");
env.create_file(testFile, 42);
// Change the permissions so we can no longer iterate
permissions(testFile, perms::none);
// Check that the construction fails when skip_permissions_denied is
// not given.
{
std::error_code ec;
RDI it(testFile, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == RDI{});
}
// Check that construction still fails when 'skip_permissions_denied' is given
// because we tried to open a file and not a directory.
{
std::error_code ec;
RDI it(testFile, directory_options::skip_permission_denied, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == RDI{});
}
}
TEST_CASE(test_open_on_empty_directory_equals_end)
{
scoped_test_env env;
const path testDir = env.make_env_path("dir1");
env.create_dir(testDir);
const RDI endIt;
{
std::error_code ec;
RDI it(testDir, ec);
TEST_CHECK(!ec);
TEST_CHECK(it == endIt);
}
{
RDI it(testDir);
TEST_CHECK(it == endIt);
}
}
TEST_CASE(test_open_on_directory_succeeds)
{
const path testDir = StaticEnv::Dir;
std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
std::end( StaticEnv::DirIterationList));
const RDI endIt{};
{
std::error_code ec;
RDI it(testDir, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it != endIt);
TEST_CHECK(dir_contents.count(*it));
}
{
RDI it(testDir);
TEST_CHECK(it != endIt);
TEST_CHECK(dir_contents.count(*it));
}
}
TEST_CASE(test_open_on_file_fails)
{
const path testFile = StaticEnv::File;
const RDI endIt{};
{
std::error_code ec;
RDI it(testFile, ec);
TEST_REQUIRE(ec);
TEST_CHECK(it == endIt);
}
{
TEST_CHECK_THROW(filesystem_error, RDI(testFile));
}
}
TEST_CASE(test_options_post_conditions)
{
const path goodDir = StaticEnv::Dir;
const path badDir = StaticEnv::DNE;
{
std::error_code ec;
RDI it1(goodDir, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it1.options() == directory_options::none);
RDI it2(badDir, ec);
TEST_REQUIRE(ec);
TEST_REQUIRE(it2 == RDI{});
}
{
std::error_code ec;
const directory_options opts = directory_options::skip_permission_denied;
RDI it1(goodDir, opts, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it1.options() == opts);
RDI it2(badDir, opts, ec);
TEST_REQUIRE(ec);
TEST_REQUIRE(it2 == RDI{});
}
{
RDI it(goodDir);
TEST_CHECK(it.options() == directory_options::none);
}
{
const directory_options opts = directory_options::follow_directory_symlink;
RDI it(goodDir, opts);
TEST_CHECK(it.options() == opts);
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class recursive_directory_iterator
// int depth() const
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(recursive_directory_iterator_depth_tests)
TEST_CASE(test_depth)
{
const path testDir = StaticEnv::Dir;
const path DirDepth1 = StaticEnv::Dir2;
const path DirDepth2 = StaticEnv::Dir3;
const recursive_directory_iterator endIt{};
std::error_code ec;
recursive_directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
TEST_CHECK(it.depth() == 0);
bool seen_d1, seen_d2;
seen_d1 = seen_d2 = false;
while (it != endIt) {
const path entry = *it;
const path parent = entry.parent_path();
if (parent == testDir) {
TEST_CHECK(it.depth() == 0);
} else if (parent == DirDepth1) {
TEST_CHECK(it.depth() == 1);
seen_d1 = true;
} else if (parent == DirDepth2) {
TEST_CHECK(it.depth() == 2);
seen_d2 = true;
} else {
TEST_CHECK(!"Unexpected depth while iterating over static env");
}
++it;
}
TEST_REQUIRE(seen_d1 && seen_d2);
TEST_CHECK(it == endIt);
}
TEST_SUITE_END()

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class recursive_directory_iterator
// void disable_recursion_pending();
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(recursive_directory_iterator_disable_recursion_pending_tests)
// NOTE: The main semantics of disable_recursion_pending are tested
// in the 'recursion_pending()' tests.
TEST_CASE(basic_test)
{
recursive_directory_iterator it(StaticEnv::Dir);
TEST_REQUIRE(it.recursion_pending() == true);
it.disable_recursion_pending();
TEST_CHECK(it.recursion_pending() == false);
it.disable_recursion_pending();
TEST_CHECK(it.recursion_pending() == false);
}
TEST_SUITE_END()

View File

@ -0,0 +1,494 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class recursive_directory_iterator
// recursive_directory_iterator& operator++();
// recursive_directory_iterator& increment(error_code& ec) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(recursive_directory_iterator_increment_tests)
TEST_CASE(test_increment_signatures)
{
recursive_directory_iterator d; ((void)d);
std::error_code ec; ((void)ec);
ASSERT_SAME_TYPE(decltype(++d), recursive_directory_iterator&);
ASSERT_NOT_NOEXCEPT(++d);
ASSERT_SAME_TYPE(decltype(d.increment(ec)), recursive_directory_iterator&);
ASSERT_NOT_NOEXCEPT(d.increment(ec));
}
TEST_CASE(test_prefix_increment)
{
const path testDir = StaticEnv::Dir;
const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList),
std::end( StaticEnv::RecDirIterationList));
const recursive_directory_iterator endIt{};
std::error_code ec;
recursive_directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
std::set<path> unseen_entries = dir_contents;
while (!unseen_entries.empty()) {
TEST_REQUIRE(it != endIt);
const path entry = *it;
TEST_REQUIRE(unseen_entries.erase(entry) == 1);
recursive_directory_iterator& it_ref = ++it;
TEST_CHECK(&it_ref == &it);
}
TEST_CHECK(it == endIt);
}
TEST_CASE(test_postfix_increment)
{
const path testDir = StaticEnv::Dir;
const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList),
std::end( StaticEnv::RecDirIterationList));
const recursive_directory_iterator endIt{};
std::error_code ec;
recursive_directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
std::set<path> unseen_entries = dir_contents;
while (!unseen_entries.empty()) {
TEST_REQUIRE(it != endIt);
const path entry = *it;
TEST_REQUIRE(unseen_entries.erase(entry) == 1);
const path entry2 = *it++;
TEST_CHECK(entry2 == entry);
}
TEST_CHECK(it == endIt);
}
TEST_CASE(test_increment_method)
{
const path testDir = StaticEnv::Dir;
const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList),
std::end( StaticEnv::RecDirIterationList));
const recursive_directory_iterator endIt{};
std::error_code ec;
recursive_directory_iterator it(testDir, ec);
TEST_REQUIRE(!ec);
std::set<path> unseen_entries = dir_contents;
while (!unseen_entries.empty()) {
TEST_REQUIRE(it != endIt);
const path entry = *it;
TEST_REQUIRE(unseen_entries.erase(entry) == 1);
recursive_directory_iterator& it_ref = it.increment(ec);
TEST_REQUIRE(!ec);
TEST_CHECK(&it_ref == &it);
}
TEST_CHECK(it == endIt);
}
TEST_CASE(test_follow_symlinks)
{
const path testDir = StaticEnv::Dir;
auto const& IterList = StaticEnv::RecDirFollowSymlinksIterationList;
const std::set<path> dir_contents(std::begin(IterList), std::end(IterList));
const recursive_directory_iterator endIt{};
std::error_code ec;
recursive_directory_iterator it(testDir,
directory_options::follow_directory_symlink, ec);
TEST_REQUIRE(!ec);
std::set<path> unseen_entries = dir_contents;
while (!unseen_entries.empty()) {
TEST_REQUIRE(it != endIt);
const path entry = *it;
TEST_REQUIRE(unseen_entries.erase(entry) == 1);
recursive_directory_iterator& it_ref = it.increment(ec);
TEST_REQUIRE(!ec);
TEST_CHECK(&it_ref == &it);
}
TEST_CHECK(it == endIt);
}
TEST_CASE(access_denied_on_recursion_test_case)
{
using namespace fs;
scoped_test_env env;
const path testFiles[] = {
env.create_dir("dir1"),
env.create_dir("dir1/dir2"),
env.create_file("dir1/dir2/file1"),
env.create_file("dir1/file2")
};
const path startDir = testFiles[0];
const path permDeniedDir = testFiles[1];
const path otherFile = testFiles[3];
auto SkipEPerm = directory_options::skip_permission_denied;
// Change the permissions so we can no longer iterate
permissions(permDeniedDir, perms::none);
const recursive_directory_iterator endIt;
// Test that recursion resulting in a "EACCESS" error is not ignored
// by default.
{
std::error_code ec = GetTestEC();
recursive_directory_iterator it(startDir, ec);
TEST_REQUIRE(ec != GetTestEC());
TEST_REQUIRE(!ec);
while (it != endIt && it->path() != permDeniedDir)
++it;
TEST_REQUIRE(it != endIt);
TEST_REQUIRE(*it == permDeniedDir);
it.increment(ec);
TEST_CHECK(ec);
TEST_CHECK(it == endIt);
}
// Same as above but test operator++().
{
std::error_code ec = GetTestEC();
recursive_directory_iterator it(startDir, ec);
TEST_REQUIRE(!ec);
while (it != endIt && it->path() != permDeniedDir)
++it;
TEST_REQUIRE(it != endIt);
TEST_REQUIRE(*it == permDeniedDir);
TEST_REQUIRE_THROW(filesystem_error, ++it);
}
// Test that recursion resulting in a "EACCESS" error is ignored when the
// correct options are given to the constructor.
{
std::error_code ec = GetTestEC();
recursive_directory_iterator it(startDir, SkipEPerm, ec);
TEST_REQUIRE(!ec);
TEST_REQUIRE(it != endIt);
bool seenOtherFile = false;
if (*it == otherFile) {
++it;
seenOtherFile = true;
TEST_REQUIRE (it != endIt);
}
TEST_REQUIRE(*it == permDeniedDir);
ec = GetTestEC();
it.increment(ec);
TEST_REQUIRE(!ec);
if (seenOtherFile) {
TEST_CHECK(it == endIt);
} else {
TEST_CHECK(it != endIt);
TEST_CHECK(*it == otherFile);
}
}
// Test that construction resulting in a "EACCESS" error is not ignored
// by default.
{
std::error_code ec;
recursive_directory_iterator it(permDeniedDir, ec);
TEST_REQUIRE(ec);
TEST_REQUIRE(it == endIt);
}
// Same as above but testing the throwing constructors
{
TEST_REQUIRE_THROW(filesystem_error,
recursive_directory_iterator(permDeniedDir));
}
// Test that construction resulting in a "EACCESS" error constructs the
// end iterator when the correct options are given.
{
std::error_code ec = GetTestEC();
recursive_directory_iterator it(permDeniedDir, SkipEPerm, ec);
TEST_REQUIRE(!ec);
TEST_REQUIRE(it == endIt);
}
}
// See llvm.org/PR35078
TEST_CASE(test_PR35078)
{
using namespace fs;
scoped_test_env env;
const path testFiles[] = {
env.create_dir("dir1"),
env.create_dir("dir1/dir2"),
env.create_dir("dir1/dir2/dir3"),
env.create_file("dir1/file1"),
env.create_file("dir1/dir2/dir3/file2")
};
const path startDir = testFiles[0];
const path permDeniedDir = testFiles[1];
const path nestedDir = testFiles[2];
const path nestedFile = testFiles[3];
// Change the permissions so we can no longer iterate
permissions(permDeniedDir,
perms::group_exec|perms::owner_exec|perms::others_exec,
perm_options::remove);
const std::error_code eacess_ec =
std::make_error_code(std::errc::permission_denied);
std::error_code ec = GetTestEC();
const recursive_directory_iterator endIt;
auto SetupState = [&](bool AllowEAccess, bool& SeenFile3) {
SeenFile3 = false;
auto Opts = AllowEAccess ? directory_options::skip_permission_denied
: directory_options::none;
recursive_directory_iterator it(startDir, Opts, ec);
while (!ec && it != endIt && *it != nestedDir) {
if (*it == nestedFile)
SeenFile3 = true;
it.increment(ec);
}
return it;
};
{
bool SeenNestedFile = false;
recursive_directory_iterator it = SetupState(false, SeenNestedFile);
TEST_REQUIRE(it != endIt);
TEST_REQUIRE(*it == nestedDir);
ec = GetTestEC();
it.increment(ec);
TEST_CHECK(ec);
TEST_CHECK(ec == eacess_ec);
TEST_CHECK(it == endIt);
}
{
bool SeenNestedFile = false;
recursive_directory_iterator it = SetupState(true, SeenNestedFile);
TEST_REQUIRE(it != endIt);
TEST_REQUIRE(*it == nestedDir);
ec = GetTestEC();
it.increment(ec);
TEST_CHECK(!ec);
if (SeenNestedFile) {
TEST_CHECK(it == endIt);
} else {
TEST_REQUIRE(it != endIt);
TEST_CHECK(*it == nestedFile);
}
}
{
bool SeenNestedFile = false;
recursive_directory_iterator it = SetupState(false, SeenNestedFile);
TEST_REQUIRE(it != endIt);
TEST_REQUIRE(*it == nestedDir);
ExceptionChecker Checker(std::errc::permission_denied,
"recursive_directory_iterator::operator++()",
format_string("attempting recursion into \"%s\"",
nestedDir.native()));
TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ++it);
}
}
// See llvm.org/PR35078
TEST_CASE(test_PR35078_with_symlink)
{
using namespace fs;
scoped_test_env env;
const path testFiles[] = {
env.create_dir("dir1"),
env.create_file("dir1/file1"),
env.create_dir("sym_dir"),
env.create_dir("sym_dir/nested_sym_dir"),
env.create_symlink("sym_dir/nested_sym_dir", "dir1/dir2"),
env.create_dir("sym_dir/dir1"),
env.create_dir("sym_dir/dir1/dir2"),
};
// const unsigned TestFilesSize = sizeof(testFiles) / sizeof(testFiles[0]);
const path startDir = testFiles[0];
const path nestedFile = testFiles[1];
const path permDeniedDir = testFiles[2];
const path symDir = testFiles[4];
// Change the permissions so we can no longer iterate
permissions(permDeniedDir,
perms::group_exec|perms::owner_exec|perms::others_exec,
perm_options::remove);
const std::error_code eacess_ec =
std::make_error_code(std::errc::permission_denied);
std::error_code ec = GetTestEC();
const recursive_directory_iterator endIt;
auto SetupState = [&](bool AllowEAccess, bool FollowSym, bool& SeenFile3) {
SeenFile3 = false;
auto Opts = AllowEAccess ? directory_options::skip_permission_denied
: directory_options::none;
if (FollowSym)
Opts |= directory_options::follow_directory_symlink;
recursive_directory_iterator it(startDir, Opts, ec);
while (!ec && it != endIt && *it != symDir) {
if (*it == nestedFile)
SeenFile3 = true;
it.increment(ec);
}
return it;
};
struct {
bool SkipPermDenied;
bool FollowSymlinks;
bool ExpectSuccess;
} TestCases[] = {
// Passing cases
{false, false, true}, {true, true, true}, {true, false, true},
// Failing cases
{false, true, false}
};
for (auto TC : TestCases) {
bool SeenNestedFile = false;
recursive_directory_iterator it = SetupState(TC.SkipPermDenied,
TC.FollowSymlinks,
SeenNestedFile);
TEST_REQUIRE(!ec);
TEST_REQUIRE(it != endIt);
TEST_REQUIRE(*it == symDir);
ec = GetTestEC();
it.increment(ec);
if (TC.ExpectSuccess) {
TEST_CHECK(!ec);
if (SeenNestedFile) {
TEST_CHECK(it == endIt);
} else {
TEST_REQUIRE(it != endIt);
TEST_CHECK(*it == nestedFile);
}
} else {
TEST_CHECK(ec);
TEST_CHECK(ec == eacess_ec);
TEST_CHECK(it == endIt);
}
}
}
// See llvm.org/PR35078
TEST_CASE(test_PR35078_with_symlink_file)
{
using namespace fs;
scoped_test_env env;
const path testFiles[] = {
env.create_dir("dir1"),
env.create_dir("dir1/dir2"),
env.create_file("dir1/file2"),
env.create_dir("sym_dir"),
env.create_dir("sym_dir/sdir1"),
env.create_file("sym_dir/sdir1/sfile1"),
env.create_symlink("sym_dir/sdir1/sfile1", "dir1/dir2/file1")
};
const unsigned TestFilesSize = sizeof(testFiles) / sizeof(testFiles[0]);
const path startDir = testFiles[0];
const path nestedDir = testFiles[1];
const path nestedFile = testFiles[2];
const path permDeniedDir = testFiles[3];
const path symFile = testFiles[TestFilesSize - 1];
// Change the permissions so we can no longer iterate
permissions(permDeniedDir,
perms::group_exec|perms::owner_exec|perms::others_exec,
perm_options::remove);
const std::error_code eacess_ec =
std::make_error_code(std::errc::permission_denied);
std::error_code ec = GetTestEC();
const recursive_directory_iterator EndIt;
auto SetupState = [&](bool AllowEAccess, bool FollowSym, bool& SeenNestedFile) {
SeenNestedFile = false;
auto Opts = AllowEAccess ? directory_options::skip_permission_denied
: directory_options::none;
if (FollowSym)
Opts |= directory_options::follow_directory_symlink;
recursive_directory_iterator it(startDir, Opts, ec);
while (!ec && it != EndIt && *it != nestedDir) {
if (*it == nestedFile)
SeenNestedFile = true;
it.increment(ec);
}
return it;
};
struct {
bool SkipPermDenied;
bool FollowSymlinks;
bool ExpectSuccess;
} TestCases[] = {
// Passing cases
{false, false, true}, {true, true, true}, {true, false, true},
// Failing cases
{false, true, false}
};
for (auto TC : TestCases){
bool SeenNestedFile = false;
recursive_directory_iterator it = SetupState(TC.SkipPermDenied,
TC.FollowSymlinks,
SeenNestedFile);
TEST_REQUIRE(!ec);
TEST_REQUIRE(it != EndIt);
TEST_REQUIRE(*it == nestedDir);
ec = GetTestEC();
it.increment(ec);
TEST_REQUIRE(it != EndIt);
TEST_CHECK(!ec);
TEST_CHECK(*it == symFile);
ec = GetTestEC();
it.increment(ec);
if (TC.ExpectSuccess) {
if (!SeenNestedFile) {
TEST_CHECK(!ec);
TEST_REQUIRE(it != EndIt);
TEST_CHECK(*it == nestedFile);
ec = GetTestEC();
it.increment(ec);
}
TEST_CHECK(!ec);
TEST_CHECK(it == EndIt);
} else {
TEST_CHECK(ec);
TEST_CHECK(ec == eacess_ec);
TEST_CHECK(it == EndIt);
}
}
}
TEST_SUITE_END()

View File

@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class recursive_directory_iterator
// recursive_directory_iterator(recursive_directory_iterator&&) noexcept;
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
using namespace fs;
TEST_SUITE(recursive_directory_iterator_move_construct_tests)
TEST_CASE(test_constructor_signature)
{
using D = recursive_directory_iterator;
static_assert(std::is_nothrow_move_constructible<D>::value, "");
}
TEST_CASE(test_move_end_iterator)
{
const recursive_directory_iterator endIt;
recursive_directory_iterator endIt2{};
recursive_directory_iterator it(std::move(endIt2));
TEST_CHECK(it == endIt);
TEST_CHECK(endIt2 == endIt);
}
TEST_CASE(test_move_valid_iterator)
{
const path testDir = StaticEnv::Dir;
const recursive_directory_iterator endIt{};
// build 'it' up with "interesting" non-default state so we can test
// that it gets copied. We want to get 'it' into a state such that:
// it.options() != directory_options::none
// it.depth() != 0
// it.recursion_pending() != true
const directory_options opts = directory_options::skip_permission_denied;
recursive_directory_iterator it(testDir, opts);
TEST_REQUIRE(it != endIt);
while (it.depth() == 0) {
++it;
TEST_REQUIRE(it != endIt);
}
it.disable_recursion_pending();
TEST_CHECK(it.options() == opts);
TEST_CHECK(it.depth() == 1);
TEST_CHECK(it.recursion_pending() == false);
const path entry = *it;
// OPERATION UNDER TEST //
const recursive_directory_iterator it2(std::move(it));
// ------------------- //
TEST_REQUIRE(it2 != endIt);
TEST_CHECK(*it2 == entry);
TEST_CHECK(it2.depth() == 1);
TEST_CHECK(it2.recursion_pending() == false);
}
TEST_SUITE_END()

View File

@ -0,0 +1,168 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// <filesystem>
// class recursive_directory_iterator
// recursive_directory_iterator& operator=(recursive_directory_iterator const&);
#include "filesystem_include.hpp"
#include <type_traits>
#include <set>
#include <cassert>
#include "test_macros.h"
#include "rapid-cxx-test.hpp"
#include "filesystem_test_helper.hpp"
// The filesystem specification explicitly allows for self-move on
// the directory iterators. Turn off this warning so we can test it.
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wself-move"
#endif
using namespace fs;
TEST_SUITE(recursive_directory_iterator_move_assign_tests)
recursive_directory_iterator createInterestingIterator()
// Create an "interesting" iterator where all fields are
// in a non-default state. The returned 'it' is in a
// state such that:
// it.options() == directory_options::skip_permission_denied
// it.depth() == 1
// it.recursion_pending() == true
{
const path testDir = StaticEnv::Dir;
const recursive_directory_iterator endIt;
recursive_directory_iterator it(testDir,
directory_options::skip_permission_denied);
TEST_ASSERT(it != endIt);
while (it.depth() != 1) {
++it;
TEST_ASSERT(it != endIt);
}
TEST_ASSERT(it.depth() == 1);
it.disable_recursion_pending();
return it;
}
recursive_directory_iterator createDifferentInterestingIterator()
// Create an "interesting" iterator where all fields are
// in a non-default state. The returned 'it' is in a
// state such that:
// it.options() == directory_options::follow_directory_symlink
// it.depth() == 2
// it.recursion_pending() == false
{
const path testDir = StaticEnv::Dir;
const recursive_directory_iterator endIt;
recursive_directory_iterator it(testDir,
directory_options::follow_directory_symlink);
TEST_ASSERT(it != endIt);
while (it.depth() != 2) {
++it;
TEST_ASSERT(it != endIt);
}
TEST_ASSERT(it.depth() == 2);
return it;
}
TEST_CASE(test_assignment_signature)
{
using D = recursive_directory_iterator;
static_assert(std::is_nothrow_move_assignable<D>::value, "");
}
TEST_CASE(test_move_to_end_iterator)
{
const recursive_directory_iterator endIt;
recursive_directory_iterator from = createInterestingIterator();
const recursive_directory_iterator from_copy(from);
const path entry = *from;
recursive_directory_iterator to;
to = std::move(from);
TEST_REQUIRE(to != endIt);
TEST_CHECK(*to == entry);
TEST_CHECK(to.options() == from_copy.options());
TEST_CHECK(to.depth() == from_copy.depth());
TEST_CHECK(to.recursion_pending() == from_copy.recursion_pending());
TEST_CHECK(from == endIt || from == to);
}
TEST_CASE(test_move_from_end_iterator)
{
recursive_directory_iterator from;
recursive_directory_iterator to = createInterestingIterator();
to = std::move(from);
TEST_REQUIRE(to == from);
TEST_CHECK(to == recursive_directory_iterator{});
}
TEST_CASE(test_move_valid_iterator)
{
const recursive_directory_iterator endIt;
recursive_directory_iterator it = createInterestingIterator();
const recursive_directory_iterator it_copy(it);
const path entry = *it;
recursive_directory_iterator it2 = createDifferentInterestingIterator();
const recursive_directory_iterator it2_copy(it2);
TEST_REQUIRE(it2 != it);
TEST_CHECK(it2.options() != it.options());
TEST_CHECK(it2.depth() != it.depth());
TEST_CHECK(it2.recursion_pending() != it.recursion_pending());
TEST_CHECK(*it2 != entry);
it2 = std::move(it);
TEST_REQUIRE(it2 != it2_copy && it2 != endIt);
TEST_CHECK(it2.options() == it_copy.options());
TEST_CHECK(it2.depth() == it_copy.depth());
TEST_CHECK(it2.recursion_pending() == it_copy.recursion_pending());
TEST_CHECK(*it2 == entry);
TEST_CHECK(it == endIt || it == it2);
}
TEST_CASE(test_returns_reference_to_self)
{
recursive_directory_iterator it;
recursive_directory_iterator it2;
recursive_directory_iterator& ref = (it2 = std::move(it));
TEST_CHECK(&ref == &it2);
}
TEST_CASE(test_self_move)
{
// Create two non-equal iterators that have exactly the same state.
recursive_directory_iterator it = createInterestingIterator();
recursive_directory_iterator it2 = createInterestingIterator();
TEST_CHECK(it != it2);
TEST_CHECK(it2.options() == it.options());
TEST_CHECK(it2.depth() == it.depth());
TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
TEST_CHECK(*it2 == *it);
it = std::move(it);
TEST_CHECK(it2.options() == it.options());
TEST_CHECK(it2.depth() == it.depth());
TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
TEST_CHECK(*it2 == *it);
}
TEST_SUITE_END()

Some files were not shown because too many files have changed in this diff Show More