mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-26 03:15:19 +00:00
Add Filesystem TS -- Complete
Add the completed std::experimental::filesystem implementation and tests. The implementation supports C++11 or newer. The TS is built as part of 'libc++experimental.a'. Users of the TS need to manually link this library. Building and testing the TS can be disabled using the CMake option '-DLIBCXX_ENABLE_FILESYSTEM=OFF'. Currently 'libc++experimental.a' is not installed by default. To turn on the installation of the library use '-DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON'. llvm-svn: 273034
This commit is contained in:
parent
7a5813597d
commit
c79795874a
@ -53,6 +53,8 @@ MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
|
||||
option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON)
|
||||
option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
|
||||
option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON)
|
||||
option(LIBCXX_ENABLE_FILESYSTEM
|
||||
"Build filesystem as part of libc++experimental.a" ${LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY})
|
||||
option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
|
||||
option(LIBCXX_INCLUDE_DOCS "Build the libc++ documentation." ${LLVM_INCLUDE_DOCS})
|
||||
set(LIBCXX_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
|
||||
@ -166,6 +168,11 @@ option(LIBCXX_CONFIGURE_IDE "Configure libcxx for use within an IDE"
|
||||
# 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)
|
||||
@ -302,7 +309,7 @@ add_compile_flags_if_supported(-nostdinc++)
|
||||
add_definitions(-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
add_compile_flags_if_supported(
|
||||
-Wall -W -Wwrite-strings
|
||||
-Wno-unused-parameter -Wno-long-long
|
||||
-Wno-unused-parameter -Wno-long-long -Wno-user-defined-literals
|
||||
-Werror=return-type)
|
||||
if (LIBCXX_ENABLE_WERROR)
|
||||
add_compile_flags_if_supported(-Werror)
|
||||
|
@ -177,6 +177,14 @@ libc++experimental Specific Options
|
||||
Install libc++experimental.a alongside libc++.
|
||||
|
||||
|
||||
.. option:: LIBCXX_ENABLE_FILESYSTEM:BOOL
|
||||
|
||||
**Default**: ``LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY``
|
||||
|
||||
Build filesystem as part of libc++experimental.a. This allows filesystem
|
||||
to be disabled without turning off the entire experimental library.
|
||||
|
||||
|
||||
.. _ABI Library Specific Options:
|
||||
|
||||
ABI Library Specific Options
|
||||
|
@ -33,4 +33,14 @@
|
||||
namespace chrono { namespace experimental { inline namespace fundamentals_v1 {
|
||||
#define _LIBCPP_END_NAMESPACE_CHRONO_LFTS _LIBCPP_END_NAMESPACE_STD } } }
|
||||
|
||||
#define _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM \
|
||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL namespace filesystem { \
|
||||
inline namespace v1 {
|
||||
|
||||
#define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM \
|
||||
} } _LIBCPP_END_NAMESPACE_EXPERIMENTAL
|
||||
|
||||
|
||||
#define _VSTD_FS ::std::experimental::filesystem::v1
|
||||
|
||||
#endif
|
||||
|
2050
libcxx/include/experimental/filesystem
Normal file
2050
libcxx/include/experimental/filesystem
Normal file
File diff suppressed because it is too large
Load Diff
@ -512,8 +512,6 @@ put_time(const tm* __tm, const _CharT* __fmt)
|
||||
return __iom_t10<_CharT>(__tm, __fmt);
|
||||
}
|
||||
|
||||
#if _LIBCPP_STD_VER > 11
|
||||
|
||||
template <class _CharT, class _Traits, class _ForwardIterator>
|
||||
std::basic_ostream<_CharT, _Traits> &
|
||||
__quoted_output ( basic_ostream<_CharT, _Traits> &__os,
|
||||
@ -631,21 +629,42 @@ quoted ( const _CharT *__s, _CharT __delim = _CharT('"'), _CharT __escape =_Char
|
||||
return __quoted_output_proxy<_CharT, const _CharT *> ( __s, __end, __delim, __escape );
|
||||
}
|
||||
|
||||
|
||||
template <class _CharT, class _Traits, class _Allocator>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator>
|
||||
__quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
|
||||
{
|
||||
return __quoted_output_proxy<_CharT,
|
||||
typename basic_string <_CharT, _Traits, _Allocator>::const_iterator>
|
||||
( __s.cbegin(), __s.cend (), __delim, __escape );
|
||||
}
|
||||
|
||||
template <class _CharT, class _Traits, class _Allocator>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__quoted_proxy<_CharT, _Traits, _Allocator>
|
||||
__quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
|
||||
{
|
||||
return __quoted_proxy<_CharT, _Traits, _Allocator>( __s, __delim, __escape );
|
||||
}
|
||||
|
||||
|
||||
#if _LIBCPP_STD_VER > 11
|
||||
|
||||
template <class _CharT, class _Traits, class _Allocator>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator>
|
||||
quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
|
||||
{
|
||||
return __quoted_output_proxy<_CharT,
|
||||
typename basic_string <_CharT, _Traits, _Allocator>::const_iterator>
|
||||
( __s.cbegin(), __s.cend (), __delim, __escape );
|
||||
return __quoted(__s, __delim, __escape);
|
||||
}
|
||||
|
||||
template <class _CharT, class _Traits, class _Allocator>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__quoted_proxy<_CharT, _Traits, _Allocator>
|
||||
quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
|
||||
{
|
||||
return __quoted_proxy<_CharT, _Traits, _Allocator>( __s, __delim, __escape );
|
||||
return __quoted(__s, __delim, __escape);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -154,7 +154,10 @@ set_target_properties(cxx
|
||||
|
||||
if (LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
|
||||
file(GLOB LIBCXX_EXPERIMENTAL_SOURCES ../src/experimental/*.cpp)
|
||||
add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES})
|
||||
if (LIBCXX_ENABLE_FILESYSTEM)
|
||||
file(GLOB LIBCXX_FILESYSTEM_SOURCES ../src/experimental/filesystem/*.cpp)
|
||||
endif()
|
||||
add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES} ${LIBCXX_FILESYSTEM_SOURCES})
|
||||
target_link_libraries(cxx_experimental cxx)
|
||||
|
||||
set(experimental_flags "${LIBCXX_COMPILE_FLAGS}")
|
||||
|
256
libcxx/src/experimental/filesystem/directory_iterator.cpp
Normal file
256
libcxx/src/experimental/filesystem/directory_iterator.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
#include "experimental/filesystem"
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
|
||||
|
||||
namespace { namespace detail {
|
||||
|
||||
inline error_code capture_errno() {
|
||||
_LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
|
||||
return error_code{errno, std::generic_category()};
|
||||
}
|
||||
|
||||
template <class ...Args>
|
||||
inline bool capture_error_or_throw(std::error_code* user_ec,
|
||||
const char* msg, Args&&... args)
|
||||
{
|
||||
std::error_code my_ec = capture_errno();
|
||||
if (user_ec) {
|
||||
*user_ec = my_ec;
|
||||
return true;
|
||||
}
|
||||
__libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec));
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ...Args>
|
||||
inline bool set_or_throw(std::error_code& my_ec,
|
||||
std::error_code* user_ec,
|
||||
const char* msg, Args&&... args)
|
||||
{
|
||||
if (user_ec) {
|
||||
*user_ec = my_ec;
|
||||
return true;
|
||||
}
|
||||
__libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec));
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef path::string_type string_type;
|
||||
|
||||
|
||||
inline string_type posix_readdir(DIR *dir_stream, error_code& ec) {
|
||||
struct dirent* dir_entry_ptr = nullptr;
|
||||
errno = 0; // zero errno in order to detect errors
|
||||
if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
|
||||
ec = capture_errno();
|
||||
return {};
|
||||
} else {
|
||||
ec.clear();
|
||||
return dir_entry_ptr->d_name;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace detail
|
||||
|
||||
using detail::set_or_throw;
|
||||
|
||||
class __dir_stream {
|
||||
public:
|
||||
__dir_stream() = delete;
|
||||
__dir_stream& operator=(const __dir_stream&) = delete;
|
||||
|
||||
__dir_stream(__dir_stream&& other) noexcept
|
||||
: __stream_(other.__stream_), __root_(std::move(other.__root_)),
|
||||
__entry_(std::move(other.__entry_))
|
||||
{
|
||||
other.__stream_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
__dir_stream(const path& root, directory_options opts, error_code& ec)
|
||||
: __stream_(nullptr),
|
||||
__root_(root)
|
||||
{
|
||||
if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
|
||||
ec = detail::capture_errno();
|
||||
const bool allow_eacess =
|
||||
bool(opts & directory_options::skip_permission_denied);
|
||||
if (allow_eacess && ec.value() == EACCES)
|
||||
ec.clear();
|
||||
return;
|
||||
}
|
||||
advance(ec);
|
||||
}
|
||||
|
||||
~__dir_stream() noexcept
|
||||
{ if (__stream_) close(); }
|
||||
|
||||
bool good() const noexcept { return __stream_ != nullptr; }
|
||||
|
||||
bool advance(error_code &ec) {
|
||||
while (true) {
|
||||
auto str = detail::posix_readdir(__stream_, ec);
|
||||
if (str == "." || str == "..") {
|
||||
continue;
|
||||
} else if (ec || str.empty()) {
|
||||
close();
|
||||
return false;
|
||||
} else {
|
||||
__entry_.assign(__root_ / str);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::error_code close() noexcept {
|
||||
std::error_code m_ec;
|
||||
if (::closedir(__stream_) == -1)
|
||||
m_ec = detail::capture_errno();
|
||||
__stream_ = nullptr;
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
DIR * __stream_{nullptr};
|
||||
public:
|
||||
path __root_;
|
||||
directory_entry __entry_;
|
||||
};
|
||||
|
||||
// directory_iterator
|
||||
|
||||
directory_iterator::directory_iterator(const path& p, error_code *ec,
|
||||
directory_options opts)
|
||||
{
|
||||
std::error_code m_ec;
|
||||
__imp_ = make_shared<__dir_stream>(p, opts, m_ec);
|
||||
if (ec) *ec = m_ec;
|
||||
if (!__imp_->good()) {
|
||||
__imp_.reset();
|
||||
if (m_ec)
|
||||
set_or_throw(m_ec, ec,
|
||||
"directory_iterator::directory_iterator(...)", p);
|
||||
}
|
||||
}
|
||||
|
||||
directory_iterator& directory_iterator::__increment(error_code *ec)
|
||||
{
|
||||
_LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
|
||||
std::error_code m_ec;
|
||||
if (!__imp_->advance(m_ec)) {
|
||||
__imp_.reset();
|
||||
if (m_ec)
|
||||
set_or_throw(m_ec, ec, "directory_iterator::operator++()");
|
||||
} else {
|
||||
if (ec) ec->clear();
|
||||
}
|
||||
return *this;
|
||||
|
||||
}
|
||||
|
||||
directory_entry const& directory_iterator::__deref() const {
|
||||
_LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
|
||||
return __imp_->__entry_;
|
||||
}
|
||||
|
||||
// recursive_directory_iterator
|
||||
|
||||
struct recursive_directory_iterator::__shared_imp {
|
||||
stack<__dir_stream> __stack_;
|
||||
directory_options __options_;
|
||||
};
|
||||
|
||||
recursive_directory_iterator::recursive_directory_iterator(const path& p,
|
||||
directory_options opt, error_code *ec)
|
||||
: __imp_(nullptr), __rec_(true)
|
||||
{
|
||||
std::error_code m_ec;
|
||||
__dir_stream new_s(p, opt, m_ec);
|
||||
if (m_ec) set_or_throw(m_ec, ec, "recursive_directory_iterator", p);
|
||||
if (m_ec || !new_s.good()) return;
|
||||
|
||||
__imp_ = _VSTD::make_shared<__shared_imp>();
|
||||
__imp_->__options_ = opt;
|
||||
__imp_->__stack_.push(_VSTD::move(new_s));
|
||||
}
|
||||
|
||||
void recursive_directory_iterator::__pop(error_code* ec)
|
||||
{
|
||||
_LIBCPP_ASSERT(__imp_, "Popping the end iterator");
|
||||
__imp_->__stack_.pop();
|
||||
if (__imp_->__stack_.size() == 0) {
|
||||
__imp_.reset();
|
||||
if (ec) ec->clear();
|
||||
} else {
|
||||
__advance(ec);
|
||||
}
|
||||
}
|
||||
|
||||
directory_options recursive_directory_iterator::options() const {
|
||||
return __imp_->__options_;
|
||||
}
|
||||
|
||||
int recursive_directory_iterator::depth() const {
|
||||
return __imp_->__stack_.size() - 1;
|
||||
}
|
||||
|
||||
const directory_entry& recursive_directory_iterator::__deref() const {
|
||||
return __imp_->__stack_.top().__entry_;
|
||||
}
|
||||
|
||||
recursive_directory_iterator&
|
||||
recursive_directory_iterator::__increment(error_code *ec)
|
||||
{
|
||||
if (recursion_pending()) {
|
||||
if (__try_recursion(ec) || (ec && *ec))
|
||||
return *this;
|
||||
}
|
||||
__rec_ = true;
|
||||
__advance(ec);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void recursive_directory_iterator::__advance(error_code* ec) {
|
||||
const directory_iterator end_it;
|
||||
auto& stack = __imp_->__stack_;
|
||||
std::error_code m_ec;
|
||||
while (stack.size() > 0) {
|
||||
if (stack.top().advance(m_ec)) {
|
||||
if (ec) ec->clear();
|
||||
return;
|
||||
}
|
||||
if (m_ec) break;
|
||||
stack.pop();
|
||||
}
|
||||
__imp_.reset();
|
||||
if (m_ec)
|
||||
set_or_throw(m_ec, ec, "recursive_directory_iterator::operator++()");
|
||||
}
|
||||
|
||||
bool recursive_directory_iterator::__try_recursion(error_code *ec) {
|
||||
|
||||
bool rec_sym =
|
||||
bool(options() & directory_options::follow_directory_symlink);
|
||||
auto& curr_it = __imp_->__stack_.top();
|
||||
|
||||
if (is_directory(curr_it.__entry_.status()) &&
|
||||
(!is_symlink(curr_it.__entry_.symlink_status()) || rec_sym))
|
||||
{
|
||||
std::error_code m_ec;
|
||||
__dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
|
||||
if (new_it.good()) {
|
||||
__imp_->__stack_.push(_VSTD::move(new_it));
|
||||
return true;
|
||||
}
|
||||
if (m_ec) {
|
||||
__imp_.reset();
|
||||
set_or_throw(m_ec, ec,
|
||||
"recursive_directory_iterator::operator++()");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
|
754
libcxx/src/experimental/filesystem/operations.cpp
Normal file
754
libcxx/src/experimental/filesystem/operations.cpp
Normal file
@ -0,0 +1,754 @@
|
||||
//===--------------------- filesystem/ops.cpp -----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "experimental/filesystem"
|
||||
#include "iterator"
|
||||
#include "fstream"
|
||||
#include "type_traits"
|
||||
#include "random" /* for unique_path */
|
||||
#include "cstdlib"
|
||||
#include "climits"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <fcntl.h> /* values for fchmodat */
|
||||
#if defined(__APPLE__)
|
||||
#include <sys/time.h> // for ::utimes as used in __last_write_time
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
|
||||
|
||||
filesystem_error::~filesystem_error() {}
|
||||
|
||||
|
||||
// POSIX HELPERS
|
||||
|
||||
namespace detail { namespace {
|
||||
|
||||
using value_type = path::value_type;
|
||||
using string_type = path::string_type;
|
||||
|
||||
|
||||
|
||||
inline std::error_code capture_errno() {
|
||||
_LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
|
||||
std::error_code m_ec(errno, std::generic_category());
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
void set_or_throw(std::error_code const& m_ec, std::error_code* ec,
|
||||
const char* msg, path const& p = {}, path const& p2 = {})
|
||||
{
|
||||
if (ec) {
|
||||
*ec = m_ec;
|
||||
} else {
|
||||
string msg_s("std::experimental::filesystem::");
|
||||
msg_s += msg;
|
||||
__libcpp_throw(filesystem_error(msg_s, p, p2, m_ec));
|
||||
}
|
||||
}
|
||||
|
||||
void set_or_throw(std::error_code* ec, const char* msg,
|
||||
path const& p = {}, path const& p2 = {})
|
||||
{
|
||||
return set_or_throw(capture_errno(), ec, msg, p, p2);
|
||||
}
|
||||
|
||||
perms posix_get_perms(const struct ::stat & st) noexcept {
|
||||
return static_cast<perms>(st.st_mode) & perms::mask;
|
||||
}
|
||||
|
||||
::mode_t posix_convert_perms(perms prms) {
|
||||
return static_cast< ::mode_t>(prms & perms::mask);
|
||||
}
|
||||
|
||||
file_status create_file_status(std::error_code& m_ec, path const& p,
|
||||
struct ::stat& path_stat,
|
||||
std::error_code* ec)
|
||||
{
|
||||
if (ec) *ec = m_ec;
|
||||
if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
|
||||
return file_status(file_type::not_found);
|
||||
}
|
||||
else if (m_ec) {
|
||||
set_or_throw(m_ec, ec, "posix_stat", p);
|
||||
return file_status(file_type::none);
|
||||
}
|
||||
// else
|
||||
|
||||
file_status fs_tmp;
|
||||
auto const mode = path_stat.st_mode;
|
||||
if (S_ISLNK(mode)) fs_tmp.type(file_type::symlink);
|
||||
else if (S_ISREG(mode)) fs_tmp.type(file_type::regular);
|
||||
else if (S_ISDIR(mode)) fs_tmp.type(file_type::directory);
|
||||
else if (S_ISBLK(mode)) fs_tmp.type(file_type::block);
|
||||
else if (S_ISCHR(mode)) fs_tmp.type(file_type::character);
|
||||
else if (S_ISFIFO(mode)) fs_tmp.type(file_type::fifo);
|
||||
else if (S_ISSOCK(mode)) fs_tmp.type(file_type::socket);
|
||||
else fs_tmp.type(file_type::unknown);
|
||||
|
||||
fs_tmp.permissions(detail::posix_get_perms(path_stat));
|
||||
return fs_tmp;
|
||||
}
|
||||
|
||||
file_status posix_stat(path const & p, struct ::stat& path_stat,
|
||||
std::error_code* ec)
|
||||
{
|
||||
std::error_code m_ec;
|
||||
if (::stat(p.c_str(), &path_stat) == -1)
|
||||
m_ec = detail::capture_errno();
|
||||
return create_file_status(m_ec, p, path_stat, ec);
|
||||
}
|
||||
|
||||
file_status posix_stat(path const & p, std::error_code* ec) {
|
||||
struct ::stat path_stat;
|
||||
return posix_stat(p, path_stat, ec);
|
||||
}
|
||||
|
||||
file_status posix_lstat(path const & p, struct ::stat & path_stat,
|
||||
std::error_code* ec)
|
||||
{
|
||||
std::error_code m_ec;
|
||||
if (::lstat(p.c_str(), &path_stat) == -1)
|
||||
m_ec = detail::capture_errno();
|
||||
return create_file_status(m_ec, p, path_stat, ec);
|
||||
}
|
||||
|
||||
file_status posix_lstat(path const & p, std::error_code* ec) {
|
||||
struct ::stat path_stat;
|
||||
return posix_lstat(p, path_stat, ec);
|
||||
}
|
||||
|
||||
bool stat_equivalent(struct ::stat& st1, struct ::stat& st2) {
|
||||
return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
|
||||
}
|
||||
|
||||
// DETAIL::MISC
|
||||
|
||||
|
||||
bool copy_file_impl(const path& from, const path& to, perms from_perms,
|
||||
std::error_code *ec)
|
||||
{
|
||||
std::ifstream in(from.c_str(), std::ios::binary);
|
||||
std::ofstream out(to.c_str(), std::ios::binary);
|
||||
|
||||
if (in.good() && out.good()) {
|
||||
using InIt = std::istreambuf_iterator<char>;
|
||||
using OutIt = std::ostreambuf_iterator<char>;
|
||||
InIt bin(in);
|
||||
InIt ein;
|
||||
OutIt bout(out);
|
||||
std::copy(bin, ein, bout);
|
||||
}
|
||||
if (out.fail() || in.fail()) {
|
||||
set_or_throw(make_error_code(errc::operation_not_permitted),
|
||||
ec, "copy_file", from, to);
|
||||
return false;
|
||||
}
|
||||
__permissions(to, from_perms, ec);
|
||||
// TODO what if permissions fails?
|
||||
return true;
|
||||
}
|
||||
|
||||
}} // end namespace detail
|
||||
|
||||
using detail::set_or_throw;
|
||||
|
||||
path __canonical(path const & orig_p, const path& base, std::error_code *ec)
|
||||
{
|
||||
path p = absolute(orig_p, base);
|
||||
char buff[PATH_MAX + 1];
|
||||
char *ret;
|
||||
if ((ret = ::realpath(p.c_str(), buff)) == nullptr) {
|
||||
set_or_throw(ec, "canonical", orig_p, base);
|
||||
return {};
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
return {ret};
|
||||
}
|
||||
|
||||
void __copy(const path& from, const path& to, copy_options options,
|
||||
std::error_code *ec)
|
||||
{
|
||||
const bool sym_status = bool(options &
|
||||
(copy_options::create_symlinks | copy_options::skip_symlinks));
|
||||
|
||||
const bool sym_status2 = bool(options &
|
||||
copy_options::copy_symlinks);
|
||||
|
||||
std::error_code m_ec;
|
||||
struct ::stat f_st = {};
|
||||
const file_status f = sym_status || sym_status2
|
||||
? detail::posix_lstat(from, f_st, &m_ec)
|
||||
: detail::posix_stat(from, f_st, &m_ec);
|
||||
if (m_ec)
|
||||
return set_or_throw(m_ec, ec, "copy", from, to);
|
||||
|
||||
struct ::stat t_st = {};
|
||||
const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec)
|
||||
: detail::posix_stat(to, t_st, &m_ec);
|
||||
|
||||
if (not status_known(t))
|
||||
return set_or_throw(m_ec, ec, "copy", from, to);
|
||||
|
||||
if (!exists(f) || is_other(f) || is_other(t)
|
||||
|| (is_directory(f) && is_regular_file(t))
|
||||
|| detail::stat_equivalent(f_st, t_st))
|
||||
{
|
||||
return set_or_throw(make_error_code(errc::function_not_supported),
|
||||
ec, "copy", from, to);
|
||||
}
|
||||
|
||||
if (ec) ec->clear();
|
||||
|
||||
if (is_symlink(f)) {
|
||||
if (bool(copy_options::skip_symlinks & options)) {
|
||||
// do nothing
|
||||
} else if (not exists(t)) {
|
||||
__copy_symlink(from, to, ec);
|
||||
} else {
|
||||
set_or_throw(make_error_code(errc::file_exists),
|
||||
ec, "copy", from, to);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (is_regular_file(f)) {
|
||||
if (bool(copy_options::directories_only & options)) {
|
||||
// do nothing
|
||||
}
|
||||
else if (bool(copy_options::create_symlinks & options)) {
|
||||
__create_symlink(from, to, ec);
|
||||
}
|
||||
else if (bool(copy_options::create_hard_links & options)) {
|
||||
__create_hard_link(from, to, ec);
|
||||
}
|
||||
else if (is_directory(t)) {
|
||||
__copy_file(from, to / from.filename(), options, ec);
|
||||
} else {
|
||||
__copy_file(from, to, options, ec);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (is_directory(f)) {
|
||||
if (not bool(copy_options::recursive & options) &&
|
||||
bool(copy_options::__in_recursive_copy & options))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!exists(t)) {
|
||||
// create directory to with attributes from 'from'.
|
||||
__create_directory(to, from, ec);
|
||||
if (ec && *ec) { return; }
|
||||
}
|
||||
directory_iterator it = ec ? directory_iterator(from, *ec)
|
||||
: directory_iterator(from);
|
||||
if (ec && *ec) { return; }
|
||||
std::error_code m_ec;
|
||||
for (; it != directory_iterator(); it.increment(m_ec)) {
|
||||
if (m_ec) return set_or_throw(m_ec, ec, "copy", from, to);
|
||||
__copy(it->path(), to / it->path().filename(),
|
||||
options | copy_options::__in_recursive_copy, ec);
|
||||
if (ec && *ec) { return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool __copy_file(const path& from, const path& to, copy_options options,
|
||||
std::error_code *ec)
|
||||
{
|
||||
if (ec) ec->clear();
|
||||
|
||||
std::error_code m_ec;
|
||||
auto from_st = detail::posix_stat(from, &m_ec);
|
||||
if (not is_regular_file(from_st)) {
|
||||
if (not m_ec)
|
||||
m_ec = make_error_code(errc::not_supported);
|
||||
set_or_throw(m_ec, ec, "copy_file", from, to);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto to_st = detail::posix_stat(to, &m_ec);
|
||||
if (!status_known(to_st)) {
|
||||
set_or_throw(m_ec, ec, "copy_file", from, to);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool to_exists = exists(to_st);
|
||||
if (to_exists && bool(copy_options::skip_existing & options)) {
|
||||
return false;
|
||||
}
|
||||
else if (to_exists && bool(copy_options::update_existing & options)) {
|
||||
auto from_time = __last_write_time(from, ec);
|
||||
if (ec && *ec) { return false; }
|
||||
auto to_time = __last_write_time(to, ec);
|
||||
if (ec && *ec) { return false; }
|
||||
if (from_time <= to_time) {
|
||||
return false;
|
||||
}
|
||||
return detail::copy_file_impl(from, to, from_st.permissions(), ec);
|
||||
}
|
||||
else if (!to_exists || bool(copy_options::overwrite_existing & options)) {
|
||||
return detail::copy_file_impl(from, to, from_st.permissions(), ec);
|
||||
}
|
||||
else {
|
||||
set_or_throw(make_error_code(errc::file_exists), ec, "copy", from, to);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void __copy_symlink(const path& existing_symlink, const path& new_symlink,
|
||||
std::error_code *ec)
|
||||
{
|
||||
const path real_path(__read_symlink(existing_symlink, ec));
|
||||
if (ec && *ec) { return; }
|
||||
// NOTE: proposal says you should detect if you should call
|
||||
// create_symlink or create_directory_symlink. I don't think this
|
||||
// is needed with POSIX
|
||||
__create_symlink(real_path, new_symlink, ec);
|
||||
}
|
||||
|
||||
|
||||
bool __create_directories(const path& p, std::error_code *ec)
|
||||
{
|
||||
std::error_code m_ec;
|
||||
auto const st = detail::posix_stat(p, &m_ec);
|
||||
if (!status_known(st)) {
|
||||
set_or_throw(m_ec, ec, "create_directories", p);
|
||||
return false;
|
||||
}
|
||||
else if (is_directory(st)) {
|
||||
if (ec) ec->clear();
|
||||
return false;
|
||||
}
|
||||
else if (exists(st)) {
|
||||
set_or_throw(make_error_code(errc::file_exists),
|
||||
ec, "create_directories", p);
|
||||
return false;
|
||||
}
|
||||
|
||||
const path parent = p.parent_path();
|
||||
if (!parent.empty()) {
|
||||
const file_status parent_st = status(parent, m_ec);
|
||||
if (not status_known(parent_st)) {
|
||||
set_or_throw(m_ec, ec, "create_directories", p);
|
||||
return false;
|
||||
}
|
||||
if (not exists(parent_st)) {
|
||||
__create_directories(parent, ec);
|
||||
if (ec && *ec) { return false; }
|
||||
}
|
||||
}
|
||||
return __create_directory(p, ec);
|
||||
}
|
||||
|
||||
bool __create_directory(const path& p, std::error_code *ec)
|
||||
{
|
||||
if (ec) ec->clear();
|
||||
if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
|
||||
return true;
|
||||
if (errno != EEXIST || !is_directory(p))
|
||||
set_or_throw(ec, "create_directory", p);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool __create_directory(path const & p, path const & attributes,
|
||||
std::error_code *ec)
|
||||
{
|
||||
struct ::stat attr_stat;
|
||||
std::error_code mec;
|
||||
auto st = detail::posix_stat(attributes, attr_stat, &mec);
|
||||
if (!status_known(st)) {
|
||||
set_or_throw(mec, ec, "create_directory", p, attributes);
|
||||
return false;
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
|
||||
return true;
|
||||
if (errno != EEXIST || !is_directory(p))
|
||||
set_or_throw(ec, "create_directory", p, attributes);
|
||||
return false;
|
||||
}
|
||||
|
||||
void __create_directory_symlink(path const & from, path const & to,
|
||||
std::error_code *ec){
|
||||
if (::symlink(from.c_str(), to.c_str()) != 0)
|
||||
set_or_throw(ec, "create_directory_symlink", from, to);
|
||||
else if (ec)
|
||||
ec->clear();
|
||||
}
|
||||
|
||||
void __create_hard_link(const path& from, const path& to, std::error_code *ec){
|
||||
if (::link(from.c_str(), to.c_str()) == -1)
|
||||
set_or_throw(ec, "create_hard_link", from, to);
|
||||
else if (ec)
|
||||
ec->clear();
|
||||
}
|
||||
|
||||
void __create_symlink(path const & from, path const & to, std::error_code *ec) {
|
||||
|
||||
if (::symlink(from.c_str(), to.c_str()) == -1)
|
||||
set_or_throw(ec, "create_symlink", from, to);
|
||||
else if (ec)
|
||||
ec->clear();
|
||||
}
|
||||
|
||||
path __current_path(std::error_code *ec) {
|
||||
auto size = ::pathconf(".", _PC_PATH_MAX);
|
||||
_LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
|
||||
|
||||
auto buff = std::unique_ptr<char[]>(new char[size + 1]);
|
||||
char* ret;
|
||||
if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr) {
|
||||
set_or_throw(ec, "current_path");
|
||||
return {};
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
return {buff.get()};
|
||||
}
|
||||
|
||||
void __current_path(const path& p, std::error_code *ec) {
|
||||
if (::chdir(p.c_str()) == -1)
|
||||
set_or_throw(ec, "current_path", p);
|
||||
else if (ec)
|
||||
ec->clear();
|
||||
}
|
||||
|
||||
bool __equivalent(const path& p1, const path& p2, std::error_code *ec)
|
||||
{
|
||||
std::error_code ec1, ec2;
|
||||
struct ::stat st1 = {};
|
||||
struct ::stat st2 = {};
|
||||
auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
|
||||
auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
|
||||
|
||||
if ((!exists(s1) && !exists(s2)) || (is_other(s1) && is_other(s2))) {
|
||||
set_or_throw(make_error_code(errc::not_supported), ec,
|
||||
"equivalent", p1, p2);
|
||||
return false;
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
|
||||
}
|
||||
|
||||
|
||||
std::uintmax_t __file_size(const path& p, std::error_code *ec)
|
||||
{
|
||||
std::error_code m_ec;
|
||||
struct ::stat st;
|
||||
file_status fst = detail::posix_stat(p, st, &m_ec);
|
||||
if (!exists(fst) || !is_regular_file(fst)) {
|
||||
if (!m_ec)
|
||||
m_ec = make_error_code(errc::not_supported);
|
||||
set_or_throw(m_ec, ec, "file_size", p);
|
||||
return static_cast<uintmax_t>(-1);
|
||||
}
|
||||
// is_regular_file(p) == true
|
||||
if (ec) ec->clear();
|
||||
return static_cast<std::uintmax_t>(st.st_size);
|
||||
}
|
||||
|
||||
std::uintmax_t __hard_link_count(const path& p, std::error_code *ec)
|
||||
{
|
||||
std::error_code m_ec;
|
||||
struct ::stat st;
|
||||
detail::posix_stat(p, st, &m_ec);
|
||||
if (m_ec) {
|
||||
set_or_throw(m_ec, ec, "hard_link_count", p);
|
||||
return static_cast<std::uintmax_t>(-1);
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
return static_cast<std::uintmax_t>(st.st_nlink);
|
||||
}
|
||||
|
||||
|
||||
bool __fs_is_empty(const path& p, std::error_code *ec)
|
||||
{
|
||||
if (ec) ec->clear();
|
||||
std::error_code m_ec;
|
||||
struct ::stat pst;
|
||||
auto st = detail::posix_stat(p, pst, &m_ec);
|
||||
if (is_directory(st))
|
||||
return directory_iterator(p) == directory_iterator{};
|
||||
else if (is_regular_file(st))
|
||||
return static_cast<std::uintmax_t>(pst.st_size) == 0;
|
||||
// else
|
||||
set_or_throw(m_ec, ec, "is_empty", p);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
file_time_type __last_write_time(const path& p, std::error_code *ec)
|
||||
{
|
||||
using Clock = file_time_type::clock;
|
||||
std::error_code m_ec;
|
||||
struct ::stat st;
|
||||
detail::posix_stat(p, st, &m_ec);
|
||||
if (m_ec) {
|
||||
set_or_throw(m_ec, ec, "last_write_time", p);
|
||||
return file_time_type::min();
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
return Clock::from_time_t(static_cast<std::time_t>(st.st_mtime));
|
||||
}
|
||||
|
||||
|
||||
void __last_write_time(const path& p, file_time_type new_time,
|
||||
std::error_code *ec)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
std::error_code m_ec;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// FIXME: Use utimensat when it becomes available on OS X.
|
||||
// This implementation has a race condition between determining the
|
||||
// last access time and attempting to set it to the same value using
|
||||
// ::utimes
|
||||
using Clock = file_time_type::clock;
|
||||
struct ::stat st;
|
||||
file_status fst = detail::posix_stat(p, st, &m_ec);
|
||||
if (m_ec && !status_known(fst)) {
|
||||
set_or_throw(m_ec, ec, "last_write_time", p);
|
||||
return;
|
||||
}
|
||||
auto write_dur = new_time.time_since_epoch();
|
||||
auto write_sec = duration_cast<seconds>(write_dur);
|
||||
auto access_dur = Clock::from_time_t(st.st_atime).time_since_epoch();
|
||||
auto access_sec = duration_cast<seconds>(access_dur);
|
||||
struct ::timeval tbuf[2];
|
||||
tbuf[0].tv_sec = access_sec.count();
|
||||
tbuf[0].tv_usec = duration_cast<microseconds>(access_dur - access_sec).count();
|
||||
tbuf[1].tv_sec = write_sec.count();
|
||||
tbuf[1].tv_usec = duration_cast<microseconds>(write_dur - write_sec).count();
|
||||
if (::utimes(p.c_str(), tbuf) == -1) {
|
||||
m_ec = detail::capture_errno();
|
||||
}
|
||||
#else
|
||||
auto dur_since_epoch = new_time.time_since_epoch();
|
||||
auto sec_since_epoch = duration_cast<seconds>(dur_since_epoch);
|
||||
auto ns_since_epoch = duration_cast<nanoseconds>(dur_since_epoch - sec_since_epoch);
|
||||
struct ::timespec tbuf[2];
|
||||
tbuf[0].tv_sec = 0;
|
||||
tbuf[0].tv_nsec = UTIME_OMIT;
|
||||
tbuf[1].tv_sec = sec_since_epoch.count();
|
||||
tbuf[1].tv_nsec = ns_since_epoch.count();
|
||||
if (::utimensat(AT_FDCWD, p.c_str(), tbuf, 0) == -1) {
|
||||
m_ec = detail::capture_errno();
|
||||
}
|
||||
#endif
|
||||
if (m_ec)
|
||||
set_or_throw(m_ec, ec, "last_write_time", p);
|
||||
else if (ec)
|
||||
ec->clear();
|
||||
}
|
||||
|
||||
|
||||
void __permissions(const path& p, perms prms, std::error_code *ec)
|
||||
{
|
||||
|
||||
const bool resolve_symlinks = bool(perms::resolve_symlinks & prms);
|
||||
const bool add_perms = bool(perms::add_perms & prms);
|
||||
const bool remove_perms = bool(perms::remove_perms & prms);
|
||||
|
||||
_LIBCPP_ASSERT(!(add_perms && remove_perms),
|
||||
"Both add_perms and remove_perms are set");
|
||||
|
||||
std::error_code m_ec;
|
||||
file_status st = detail::posix_lstat(p, &m_ec);
|
||||
if (m_ec) return set_or_throw(m_ec, ec, "permissions", p);
|
||||
|
||||
const bool set_sym_perms = is_symlink(st) && !resolve_symlinks;
|
||||
|
||||
if ((resolve_symlinks && is_symlink(st)) && (add_perms || remove_perms)) {
|
||||
st = detail::posix_stat(p, &m_ec);
|
||||
if (m_ec) return set_or_throw(m_ec, ec, "permissions", p);
|
||||
}
|
||||
|
||||
prms = prms & perms::mask;
|
||||
if (add_perms)
|
||||
prms |= st.permissions();
|
||||
else if (remove_perms)
|
||||
prms = st.permissions() & ~prms;
|
||||
auto real_perms = detail::posix_convert_perms(prms);
|
||||
|
||||
# if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
|
||||
const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
|
||||
if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
|
||||
# else
|
||||
if (set_sym_perms)
|
||||
return set_or_throw(make_error_code(errc::operation_not_supported),
|
||||
ec, "permissions", p);
|
||||
if (::chmod(p.c_str(), real_perms) == -1) {
|
||||
# endif
|
||||
return set_or_throw(ec, "permissions", p);
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
}
|
||||
|
||||
|
||||
path __read_symlink(const path& p, std::error_code *ec) {
|
||||
char buff[PATH_MAX + 1];
|
||||
std::error_code m_ec;
|
||||
::ssize_t ret;
|
||||
if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) {
|
||||
set_or_throw(ec, "read_symlink", p);
|
||||
return {};
|
||||
}
|
||||
_LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
|
||||
_LIBCPP_ASSERT(ret > 0, "TODO");
|
||||
if (ec) ec->clear();
|
||||
buff[ret] = 0;
|
||||
return {buff};
|
||||
}
|
||||
|
||||
|
||||
bool __remove(const path& p, std::error_code *ec) {
|
||||
if (ec) ec->clear();
|
||||
if (::remove(p.c_str()) == -1) {
|
||||
set_or_throw(ec, "remove", p);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::uintmax_t remove_all_impl(path const & p, std::error_code& ec)
|
||||
{
|
||||
const auto npos = static_cast<std::uintmax_t>(-1);
|
||||
const file_status st = __symlink_status(p, &ec);
|
||||
if (ec) return npos;
|
||||
std::uintmax_t count = 1;
|
||||
if (is_directory(st)) {
|
||||
for (directory_iterator it(p, ec); !ec && it != directory_iterator();
|
||||
it.increment(ec)) {
|
||||
auto other_count = remove_all_impl(it->path(), ec);
|
||||
if (ec) return npos;
|
||||
count += other_count;
|
||||
}
|
||||
if (ec) return npos;
|
||||
}
|
||||
if (!__remove(p, &ec)) return npos;
|
||||
return count;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
std::uintmax_t __remove_all(const path& p, std::error_code *ec) {
|
||||
std::error_code mec;
|
||||
auto count = remove_all_impl(p, mec);
|
||||
if (mec) {
|
||||
set_or_throw(mec, ec, "remove_all", p);
|
||||
return static_cast<std::uintmax_t>(-1);
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
return count;
|
||||
}
|
||||
|
||||
void __rename(const path& from, const path& to, std::error_code *ec) {
|
||||
if (::rename(from.c_str(), to.c_str()) == -1)
|
||||
set_or_throw(ec, "rename", from, to);
|
||||
else if (ec)
|
||||
ec->clear();
|
||||
}
|
||||
|
||||
void __resize_file(const path& p, std::uintmax_t size, std::error_code *ec) {
|
||||
if (::truncate(p.c_str(), static_cast<long>(size)) == -1)
|
||||
set_or_throw(ec, "resize_file", p);
|
||||
else if (ec)
|
||||
ec->clear();
|
||||
}
|
||||
|
||||
space_info __space(const path& p, std::error_code *ec) {
|
||||
space_info si;
|
||||
struct statvfs m_svfs;
|
||||
if (::statvfs(p.c_str(), &m_svfs) == -1) {
|
||||
set_or_throw(ec, "space", p);
|
||||
si.capacity = si.free = si.available =
|
||||
static_cast<std::uintmax_t>(-1);
|
||||
return si;
|
||||
}
|
||||
if (ec) ec->clear();
|
||||
// Multiply with overflow checking.
|
||||
auto do_mult = [&](std::uintmax_t& out, fsblkcnt_t other) {
|
||||
out = other * m_svfs.f_frsize;
|
||||
if (out / other != m_svfs.f_frsize || other == 0)
|
||||
out = static_cast<std::uintmax_t>(-1);
|
||||
};
|
||||
do_mult(si.capacity, m_svfs.f_blocks);
|
||||
do_mult(si.free, m_svfs.f_bfree);
|
||||
do_mult(si.available, m_svfs.f_bavail);
|
||||
return si;
|
||||
}
|
||||
|
||||
file_status __status(const path& p, std::error_code *ec) {
|
||||
return detail::posix_stat(p, ec);
|
||||
}
|
||||
|
||||
file_status __symlink_status(const path& p, std::error_code *ec) {
|
||||
return detail::posix_lstat(p, ec);
|
||||
}
|
||||
|
||||
path __system_complete(const path& p, std::error_code *ec) {
|
||||
if (ec) ec->clear();
|
||||
return absolute(p, current_path());
|
||||
}
|
||||
|
||||
path __temp_directory_path(std::error_code *ec) {
|
||||
const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
|
||||
const char* ret = nullptr;
|
||||
for (auto & ep : env_paths) {
|
||||
if ((ret = std::getenv(ep)))
|
||||
break;
|
||||
}
|
||||
path p(ret ? ret : "/tmp");
|
||||
std::error_code m_ec;
|
||||
if (is_directory(p, m_ec)) {
|
||||
if (ec) ec->clear();
|
||||
return p;
|
||||
}
|
||||
if (!m_ec || m_ec == make_error_code(errc::no_such_file_or_directory))
|
||||
m_ec = make_error_code(errc::not_a_directory);
|
||||
set_or_throw(m_ec, ec, "temp_directory_path");
|
||||
return {};
|
||||
}
|
||||
|
||||
// An absolute path is composed according to the table in [fs.op.absolute].
|
||||
path absolute(const path& p, const path& base) {
|
||||
auto root_name = p.root_name();
|
||||
auto root_dir = p.root_directory();
|
||||
|
||||
if (!root_name.empty() && !root_dir.empty())
|
||||
return p;
|
||||
|
||||
auto abs_base = base.is_absolute() ? base : absolute(base);
|
||||
|
||||
/* !has_root_name && !has_root_dir */
|
||||
if (root_name.empty() && root_dir.empty())
|
||||
{
|
||||
return abs_base / p;
|
||||
}
|
||||
else if (!root_name.empty()) /* has_root_name && !has_root_dir */
|
||||
{
|
||||
return root_name / abs_base.root_directory()
|
||||
/
|
||||
abs_base.relative_path() / p.relative_path();
|
||||
}
|
||||
else /* !has_root_name && has_root_dir */
|
||||
{
|
||||
if (abs_base.has_root_name())
|
||||
return abs_base.root_name() / p;
|
||||
// else p is absolute, return outside of block
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
|
392
libcxx/src/experimental/filesystem/path.cpp
Normal file
392
libcxx/src/experimental/filesystem/path.cpp
Normal file
@ -0,0 +1,392 @@
|
||||
//===--------------------- filesystem/path.cpp ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "experimental/filesystem"
|
||||
#include "experimental/string_view"
|
||||
#include "utility"
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
|
||||
|
||||
_LIBCPP_CONSTEXPR path::value_type path::preferred_separator;
|
||||
|
||||
|
||||
namespace { namespace parser
|
||||
{
|
||||
|
||||
using string_type = string_view;
|
||||
using value_type = path::value_type;
|
||||
|
||||
using string_view_pair = pair<string_view, string_view>;
|
||||
|
||||
// status reporting
|
||||
constexpr size_t npos = static_cast<size_t>(-1);
|
||||
|
||||
inline bool good(size_t pos) { return pos != npos; }
|
||||
|
||||
// lexical elements
|
||||
constexpr value_type preferred_separator = path::preferred_separator;
|
||||
constexpr value_type const * preferred_separator_str = "/";
|
||||
constexpr value_type const * dot = ".";
|
||||
|
||||
// forward //
|
||||
bool is_separator(string_type const &, size_t);
|
||||
bool is_root_name(const string_type&, size_t);
|
||||
bool is_root_directory(string_type const &, size_t);
|
||||
bool is_trailing_separator(string_type const &, size_t);
|
||||
|
||||
size_t start_of(string_type const &, size_t);
|
||||
size_t end_of(string_type const &, size_t);
|
||||
|
||||
size_t root_name_start(const string_type& s);
|
||||
size_t root_name_end(const string_type&);
|
||||
|
||||
size_t root_directory_start(string_type const &);
|
||||
size_t root_directory_end(string_type const &);
|
||||
|
||||
string_view_pair separate_filename(string_type const &);
|
||||
string_view extract_raw(string_type const &, size_t);
|
||||
string_view extract_preferred(string_type const &, size_t);
|
||||
|
||||
inline bool is_separator(const string_type& s, size_t pos) {
|
||||
return (pos < s.size() && s[pos] == preferred_separator);
|
||||
}
|
||||
|
||||
inline bool is_root_name(const string_type& s, size_t pos) {
|
||||
return good(pos) && pos == 0 ? root_name_start(s) == pos : false;
|
||||
}
|
||||
|
||||
inline bool is_root_directory(const string_type& s, size_t pos) {
|
||||
return good(pos) ? root_directory_start(s) == pos : false;
|
||||
}
|
||||
|
||||
inline bool is_trailing_separator(const string_type& s, size_t pos) {
|
||||
return (pos < s.size() && is_separator(s, pos) &&
|
||||
end_of(s, pos) == s.size()-1 &&
|
||||
!is_root_directory(s, pos) && !is_root_name(s, pos));
|
||||
}
|
||||
|
||||
size_t start_of(const string_type& s, size_t pos) {
|
||||
if (pos >= s.size()) return npos;
|
||||
bool in_sep = (s[pos] == preferred_separator);
|
||||
while (pos - 1 < s.size() &&
|
||||
(s[pos-1] == preferred_separator) == in_sep)
|
||||
{ --pos; }
|
||||
if (pos == 2 && !in_sep && s[0] == preferred_separator &&
|
||||
s[1] == preferred_separator)
|
||||
{ return 0; }
|
||||
return pos;
|
||||
}
|
||||
|
||||
size_t end_of(const string_type& s, size_t pos) {
|
||||
if (pos >= s.size()) return npos;
|
||||
// special case for root name
|
||||
if (pos == 0 && is_root_name(s, pos)) return root_name_end(s);
|
||||
bool in_sep = (s[pos] == preferred_separator);
|
||||
while (pos + 1 < s.size() && (s[pos+1] == preferred_separator) == in_sep)
|
||||
{ ++pos; }
|
||||
return pos;
|
||||
}
|
||||
|
||||
inline size_t root_name_start(const string_type& s) {
|
||||
return good(root_name_end(s)) ? 0 : npos;
|
||||
}
|
||||
|
||||
size_t root_name_end(const string_type& s) {
|
||||
if (s.size() < 2 || s[0] != preferred_separator
|
||||
|| s[1] != preferred_separator) {
|
||||
return npos;
|
||||
}
|
||||
if (s.size() == 2) {
|
||||
return 1;
|
||||
}
|
||||
size_t index = 2; // current position
|
||||
if (s[index] == preferred_separator) {
|
||||
return npos;
|
||||
}
|
||||
while (index + 1 < s.size() && s[index+1] != preferred_separator) {
|
||||
++index;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
size_t root_directory_start(const string_type& s) {
|
||||
size_t e = root_name_end(s);
|
||||
if (!good(e))
|
||||
return is_separator(s, 0) ? 0 : npos;
|
||||
return is_separator(s, e + 1) ? e + 1 : npos;
|
||||
}
|
||||
|
||||
size_t root_directory_end(const string_type& s) {
|
||||
size_t st = root_directory_start(s);
|
||||
if (!good(st)) return npos;
|
||||
size_t index = st;
|
||||
while (index + 1 < s.size() && s[index + 1] == preferred_separator)
|
||||
{ ++index; }
|
||||
return index;
|
||||
}
|
||||
|
||||
string_view_pair separate_filename(string_type const & s) {
|
||||
if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""};
|
||||
auto pos = s.find_last_of('.');
|
||||
if (pos == string_type::npos) return string_view_pair{s, string_view{}};
|
||||
return string_view_pair{s.substr(0, pos), s.substr(pos)};
|
||||
}
|
||||
|
||||
inline string_view extract_raw(const string_type& s, size_t pos) {
|
||||
size_t end_i = end_of(s, pos);
|
||||
if (!good(end_i)) return string_view{};
|
||||
return string_view(s).substr(pos, end_i - pos + 1);
|
||||
}
|
||||
|
||||
string_view extract_preferred(const string_type& s, size_t pos) {
|
||||
string_view raw = extract_raw(s, pos);
|
||||
if (raw.empty())
|
||||
return raw;
|
||||
if (is_trailing_separator(s, pos))
|
||||
return string_view{dot};
|
||||
if (is_separator(s, pos) && !is_root_name(s, pos))
|
||||
return string_view(preferred_separator_str);
|
||||
return raw;
|
||||
}
|
||||
|
||||
}} // namespace parser
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// path_view_iterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
namespace {
|
||||
|
||||
struct path_view_iterator {
|
||||
const string_view __s_;
|
||||
size_t __pos_;
|
||||
|
||||
explicit path_view_iterator(string_view const& __s) : __s_(__s), __pos_(__s_.empty() ? parser::npos : 0) {}
|
||||
explicit path_view_iterator(string_view const& __s, size_t __p) : __s_(__s), __pos_(__p) {}
|
||||
|
||||
string_view operator*() const {
|
||||
return parser::extract_preferred(__s_, __pos_);
|
||||
}
|
||||
|
||||
path_view_iterator& operator++() {
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
path_view_iterator& operator--() {
|
||||
decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void increment() {
|
||||
if (__pos_ == parser::npos) return;
|
||||
while (! set_position(parser::end_of(__s_, __pos_)+1))
|
||||
;
|
||||
return;
|
||||
}
|
||||
|
||||
void decrement() {
|
||||
if (__pos_ == 0) {
|
||||
set_position(0);
|
||||
}
|
||||
else if (__pos_ == parser::npos) {
|
||||
auto const str_size = __s_.size();
|
||||
set_position(parser::start_of(
|
||||
__s_, str_size != 0 ? str_size - 1 : str_size));
|
||||
} else {
|
||||
while (!set_position(parser::start_of(__s_, __pos_-1)))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
bool set_position(size_t pos) {
|
||||
if (pos >= __s_.size()) {
|
||||
__pos_ = parser::npos;
|
||||
} else {
|
||||
__pos_ = pos;
|
||||
}
|
||||
return valid_iterator_position();
|
||||
}
|
||||
|
||||
bool valid_iterator_position() const {
|
||||
if (__pos_ == parser::npos) return true; // end position is valid
|
||||
return (!parser::is_separator (__s_, __pos_) ||
|
||||
parser::is_root_directory (__s_, __pos_) ||
|
||||
parser::is_trailing_separator(__s_, __pos_) ||
|
||||
parser::is_root_name (__s_, __pos_));
|
||||
}
|
||||
|
||||
bool is_end() const { return __pos_ == parser::npos; }
|
||||
|
||||
inline bool operator==(path_view_iterator const& __p) {
|
||||
return __pos_ == __p.__pos_;
|
||||
}
|
||||
};
|
||||
|
||||
path_view_iterator pbegin(path const& p) {
|
||||
return path_view_iterator(p.native());
|
||||
}
|
||||
|
||||
path_view_iterator pend(path const& p) {
|
||||
path_view_iterator __p(p.native());
|
||||
__p.__pos_ = parser::npos;
|
||||
return __p;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// path definitions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
path & path::replace_extension(path const & replacement)
|
||||
{
|
||||
path p = extension();
|
||||
if (not p.empty()) {
|
||||
__pn_.erase(__pn_.size() - p.native().size());
|
||||
}
|
||||
if (!replacement.empty()) {
|
||||
if (replacement.native()[0] != '.') {
|
||||
__pn_ += ".";
|
||||
}
|
||||
__pn_.append(replacement.__pn_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// path.decompose
|
||||
|
||||
string_view path::__root_name() const
|
||||
{
|
||||
return parser::is_root_name(__pn_, 0)
|
||||
? parser::extract_preferred(__pn_, 0)
|
||||
: string_view{};
|
||||
}
|
||||
|
||||
string_view path::__root_directory() const
|
||||
{
|
||||
auto start_i = parser::root_directory_start(__pn_);
|
||||
if(!parser::good(start_i)) {
|
||||
return {};
|
||||
}
|
||||
return parser::extract_preferred(__pn_, start_i);
|
||||
}
|
||||
|
||||
string_view path::__relative_path() const
|
||||
{
|
||||
if (empty()) {
|
||||
return {__pn_};
|
||||
}
|
||||
auto end_i = parser::root_directory_end(__pn_);
|
||||
if (not parser::good(end_i)) {
|
||||
end_i = parser::root_name_end(__pn_);
|
||||
}
|
||||
if (not parser::good(end_i)) {
|
||||
return {__pn_};
|
||||
}
|
||||
return string_view(__pn_).substr(end_i+1);
|
||||
}
|
||||
|
||||
string_view path::__parent_path() const
|
||||
{
|
||||
if (empty() || pbegin(*this) == --pend(*this)) {
|
||||
return {};
|
||||
}
|
||||
auto end_it = --(--pend(*this));
|
||||
auto end_i = parser::end_of(__pn_, end_it.__pos_);
|
||||
return string_view(__pn_).substr(0, end_i+1);
|
||||
}
|
||||
|
||||
string_view path::__filename() const
|
||||
{
|
||||
return empty() ? string_view{} : *--pend(*this);
|
||||
}
|
||||
|
||||
string_view path::__stem() const
|
||||
{
|
||||
return parser::separate_filename(__filename()).first;
|
||||
}
|
||||
|
||||
string_view path::__extension() const
|
||||
{
|
||||
return parser::separate_filename(__filename()).second;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// path.comparisons
|
||||
int path::__compare(const value_type* __s) const {
|
||||
path_view_iterator thisIter(this->native());
|
||||
path_view_iterator sIter(__s);
|
||||
while (!thisIter.is_end() && !sIter.is_end()) {
|
||||
int res = (*thisIter).compare(*sIter);
|
||||
if (res != 0) return res;
|
||||
++thisIter; ++sIter;
|
||||
}
|
||||
if (thisIter.is_end() && sIter.is_end())
|
||||
return 0;
|
||||
if (thisIter.is_end())
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// path.nonmembers
|
||||
size_t hash_value(const path& __p) _NOEXCEPT {
|
||||
path_view_iterator thisIter(__p.native());
|
||||
struct HashPairT {
|
||||
size_t first;
|
||||
size_t second;
|
||||
};
|
||||
HashPairT hp = {0, 0};
|
||||
std::hash<string_view> hasher;
|
||||
std::__scalar_hash<decltype(hp)> pair_hasher;
|
||||
while (!thisIter.is_end()) {
|
||||
hp.second = hasher(*thisIter);
|
||||
hp.first = pair_hasher(hp);
|
||||
++thisIter;
|
||||
}
|
||||
return hp.first;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// path.itr
|
||||
path::iterator path::begin() const
|
||||
{
|
||||
path_view_iterator pit = pbegin(*this);
|
||||
iterator it;
|
||||
it.__path_ptr_ = this;
|
||||
it.__pos_ = pit.__pos_;
|
||||
it.__elem_.__assign_view(*pit);
|
||||
return it;
|
||||
}
|
||||
|
||||
path::iterator path::end() const
|
||||
{
|
||||
iterator it{};
|
||||
it.__path_ptr_ = this;
|
||||
it.__pos_ = parser::npos;
|
||||
return it;
|
||||
}
|
||||
|
||||
path::iterator& path::iterator::__increment() {
|
||||
path_view_iterator it(__path_ptr_->native(), __pos_);
|
||||
it.increment();
|
||||
__pos_ = it.__pos_;
|
||||
__elem_.__assign_view(*it);
|
||||
return *this;
|
||||
}
|
||||
|
||||
path::iterator& path::iterator::__decrement() {
|
||||
path_view_iterator it(__path_ptr_->native(), __pos_);
|
||||
it.decrement();
|
||||
__pos_ = it.__pos_;
|
||||
__elem_.__assign_view(*it);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
|
@ -11,6 +11,7 @@ set(LIBCXX_LIT_VARIANT "libcxx" CACHE STRING
|
||||
|
||||
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)
|
||||
|
@ -0,0 +1,101 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// template <class Tp> struct __is_pathable
|
||||
|
||||
// [path.req]
|
||||
// In addition to the requirements (5), function template parameters named
|
||||
// `Source` shall be one of:
|
||||
// * basic_string<_ECharT, _Traits, _Alloc>
|
||||
// * InputIterator with a value_type of _ECharT
|
||||
// * A character array, which points to a NTCTS after array-to-pointer decay.
|
||||
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
using fs::__is_pathable;
|
||||
|
||||
template <class Tp>
|
||||
struct Identity { typedef Tp type; };
|
||||
|
||||
template <class Source>
|
||||
Identity<Source> CheckSourceType(Source const&);
|
||||
|
||||
template <class Tp>
|
||||
using GetSourceType = typename decltype(CheckSourceType(std::declval<Tp>()))::type;
|
||||
|
||||
template <class Tp, class Exp,
|
||||
class ExpQual = typename std::remove_const<Exp>::type>
|
||||
using CheckPass = std::is_same<ExpQual, GetSourceType<Tp>>;
|
||||
|
||||
template <class Source>
|
||||
using CheckPassSource = std::integral_constant<bool,
|
||||
CheckPass<Source&, Source>::value &&
|
||||
CheckPass<Source const&, Source>::value &&
|
||||
CheckPass<Source&&, Source>::value &&
|
||||
CheckPass<Source const&&, Source>::value
|
||||
>;
|
||||
|
||||
template <class CharT>
|
||||
struct MakeTestType {
|
||||
using value_type = CharT;
|
||||
using string_type = std::basic_string<CharT>;
|
||||
using string_type2 = std::basic_string<CharT, std::char_traits<CharT>, min_allocator<CharT>>;
|
||||
using cstr_type = CharT* const;
|
||||
using const_cstr_type = const CharT*;
|
||||
using array_type = CharT[25];
|
||||
using const_array_type = const CharT[25];
|
||||
using iter_type = input_iterator<CharT*>;
|
||||
using bad_iter_type = input_iterator<signed char*>;
|
||||
|
||||
template <class TestT>
|
||||
static void AssertPathable() {
|
||||
static_assert(__is_pathable<TestT>::value, "");
|
||||
static_assert(CheckPassSource<TestT>::value, "cannot pass as Source const&");
|
||||
ASSERT_SAME_TYPE(CharT, typename __is_pathable<TestT>::__char_type);
|
||||
}
|
||||
|
||||
template <class TestT>
|
||||
static void AssertNotPathable() {
|
||||
static_assert(!__is_pathable<TestT>::value, "");
|
||||
}
|
||||
|
||||
static void Test() {
|
||||
AssertPathable<string_type>();
|
||||
AssertPathable<string_type2>();
|
||||
AssertPathable<cstr_type>();
|
||||
AssertPathable<const_cstr_type>();
|
||||
AssertPathable<array_type>();
|
||||
AssertPathable<const_array_type>();
|
||||
AssertPathable<iter_type>();
|
||||
|
||||
AssertNotPathable<CharT>();
|
||||
AssertNotPathable<bad_iter_type>();
|
||||
AssertNotPathable<signed char*>();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
MakeTestType<char>::Test();
|
||||
MakeTestType<wchar_t>::Test();
|
||||
MakeTestType<char16_t>::Test();
|
||||
MakeTestType<char32_t>::Test();
|
||||
}
|
3
libcxx/test/libcxx/experimental/filesystem/lit.local.cfg
Normal file
3
libcxx/test/libcxx/experimental/filesystem/lit.local.cfg
Normal 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
|
22
libcxx/test/libcxx/experimental/filesystem/version.pass.cpp
Normal file
22
libcxx/test/libcxx/experimental/filesystem/version.pass.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
#include <experimental/filesystem>
|
||||
|
||||
#ifndef _LIBCPP_VERSION
|
||||
#error _LIBCPP_VERSION not defined
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
}
|
@ -103,6 +103,7 @@ class Configuration(object):
|
||||
self.configure_execute_external()
|
||||
self.configure_ccache()
|
||||
self.configure_compile_flags()
|
||||
self.configure_filesystem_compile_flags()
|
||||
self.configure_link_flags()
|
||||
self.configure_env()
|
||||
self.configure_color_diagnostics()
|
||||
@ -427,6 +428,35 @@ class Configuration(object):
|
||||
self.config.available_features.add('libcpp-abi-unstable')
|
||||
self.cxx.compile_flags += ['-D_LIBCPP_ABI_UNSTABLE']
|
||||
|
||||
def configure_filesystem_compile_flags(self):
|
||||
enable_fs = self.get_lit_bool('enable_filesystem', default=False)
|
||||
if not enable_fs:
|
||||
return
|
||||
enable_experimental = self.get_lit_bool('enable_experimental', default=False)
|
||||
if not enable_experimental:
|
||||
self.lit_config.fatal(
|
||||
'filesystem is enabled but libc++experimental.a is not.')
|
||||
self.config.available_features.add('c++filesystem')
|
||||
static_env = os.path.join(self.libcxx_src_root, 'test', 'std',
|
||||
'experimental', 'filesystem', 'Inputs', 'static_test_env')
|
||||
assert os.path.isdir(static_env)
|
||||
self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_STATIC_TEST_ROOT="%s"' % static_env]
|
||||
|
||||
dynamic_env = os.path.join(self.libcxx_obj_root, 'test',
|
||||
'filesystem', 'Output', 'dynamic_env')
|
||||
if not os.path.isdir(dynamic_env):
|
||||
os.makedirs(dynamic_env)
|
||||
self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT="%s"' % dynamic_env]
|
||||
self.env['LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT'] = ("%s" % dynamic_env)
|
||||
|
||||
dynamic_helper = os.path.join(self.libcxx_src_root, 'test', 'support',
|
||||
'filesystem_dynamic_test_helper.py')
|
||||
assert os.path.isfile(dynamic_helper)
|
||||
|
||||
self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER="%s %s"'
|
||||
% (sys.executable, dynamic_helper)]
|
||||
|
||||
|
||||
def configure_link_flags(self):
|
||||
no_default_flags = self.get_lit_bool('no_default_flags', False)
|
||||
if not no_default_flags:
|
||||
|
@ -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@"
|
||||
|
@ -0,0 +1 @@
|
||||
dne
|
@ -0,0 +1 @@
|
||||
dir3
|
@ -0,0 +1 @@
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
@ -0,0 +1 @@
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
@ -0,0 +1 @@
|
||||
dir1
|
@ -0,0 +1 @@
|
||||
empty_file
|
@ -0,0 +1,97 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_entry
|
||||
|
||||
// directory_entry() noexcept = default;
|
||||
// directory_entry(const directory_entry&) = default;
|
||||
// directory_entry(directory_entry&&) noexcept = default;
|
||||
// explicit directory_entry(const path);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
void test_default_ctor()
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test_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.
|
||||
}
|
||||
}
|
||||
|
||||
void test_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);
|
||||
assert(p == e.path());
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_default_ctor();
|
||||
test_copy_ctor();
|
||||
test_move_ctor();
|
||||
test_path_ctor();
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
void 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void 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
|
||||
}
|
||||
}
|
||||
|
||||
void 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");
|
||||
}
|
||||
{
|
||||
assert(e.path() == p);
|
||||
e.assign(p2);
|
||||
assert(e.path() == p2 && e.path() != p);
|
||||
e.assign(p);
|
||||
assert(e.path() == p && e.path() != p2);
|
||||
}
|
||||
}
|
||||
|
||||
void test_replace_filename_method()
|
||||
{
|
||||
using namespace fs;
|
||||
const path p("/path/to/foo.exe");
|
||||
const path replace("bar.out");
|
||||
const path expect("/path/to/bar.out");
|
||||
directory_entry e(p);
|
||||
{
|
||||
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");
|
||||
}
|
||||
{
|
||||
assert(e.path() == p);
|
||||
e.replace_filename(replace);
|
||||
assert(e.path() == expect);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_copy_assign_operator();
|
||||
test_move_assign_operator();
|
||||
test_path_assign_method();
|
||||
test_replace_filename_method();
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
#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() {
|
||||
test_comparison_signatures();
|
||||
test_comparisons_simple();
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_entry
|
||||
|
||||
// const path& path() const noexcept;
|
||||
// operator const path&() const noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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() {
|
||||
test_path_method();
|
||||
test_path_conversion();
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_entry
|
||||
|
||||
// file_status status() const;
|
||||
// file_status status(error_code const&) const noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace fs;
|
||||
{
|
||||
const directory_entry e("foo");
|
||||
std::error_code ec;
|
||||
static_assert(std::is_same<decltype(e.status()), file_status>::value, "");
|
||||
static_assert(std::is_same<decltype(e.status(ec)), file_status>::value, "");
|
||||
static_assert(noexcept(e.status()) == false, "");
|
||||
static_assert(noexcept(e.status(ec)) == true, "");
|
||||
}
|
||||
auto TestFn = [](path const& p) {
|
||||
const directory_entry e(p);
|
||||
std::error_code pec, eec;
|
||||
file_status ps = fs::status(p, pec);
|
||||
file_status es = e.status(eec);
|
||||
assert(ps.type() == es.type());
|
||||
assert(ps.permissions() == es.permissions());
|
||||
assert(pec == eec);
|
||||
};
|
||||
{
|
||||
TestFn(StaticEnv::File);
|
||||
TestFn(StaticEnv::Dir);
|
||||
TestFn(StaticEnv::SymlinkToFile);
|
||||
TestFn(StaticEnv::DNE);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_entry
|
||||
|
||||
// file_status symlink_status() const;
|
||||
// file_status symlink_status(error_code&) const noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
int main() {
|
||||
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, "");
|
||||
}
|
||||
auto TestFn = [](path const& p) {
|
||||
const directory_entry e(p);
|
||||
std::error_code pec, eec;
|
||||
file_status ps = fs::symlink_status(p, pec);
|
||||
file_status es = e.symlink_status(eec);
|
||||
assert(ps.type() == es.type());
|
||||
assert(ps.permissions() == es.permissions());
|
||||
assert(pec == eec);
|
||||
};
|
||||
{
|
||||
TestFn(StaticEnv::File);
|
||||
TestFn(StaticEnv::Dir);
|
||||
TestFn(StaticEnv::SymlinkToFile);
|
||||
TestFn(StaticEnv::DNE);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// directory_iterator(directory_iterator const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,98 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// directory_iterator& operator=(directory_iterator const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,246 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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) noexcept;
|
||||
// directory_iterator(const path& p, directory_options options, error_code& ec) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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&) noexcept
|
||||
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&) noexcept
|
||||
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 std::experimental::filesystem;
|
||||
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 std::experimental::filesystem;
|
||||
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()
|
@ -0,0 +1,36 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// directory_iterator::directory_iterator() noexcept
|
||||
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
{
|
||||
static_assert(std::is_nothrow_default_constructible<fs::directory_iterator>::value, "");
|
||||
}
|
||||
{
|
||||
fs::directory_iterator d1;
|
||||
const fs::directory_iterator d2;
|
||||
assert(d1 == d2);
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// directory_iterator& operator++();
|
||||
// directory_iterator& increment(error_code& ec) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#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 std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(directory_iterator_increment_tests)
|
||||
|
||||
TEST_CASE(test_increment_signatures)
|
||||
{
|
||||
using D = directory_iterator;
|
||||
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_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()
|
@ -0,0 +1,62 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// directory_iterator(directory_iterator&&) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,110 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// directory_iterator& operator=(directory_iterator const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,61 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// directory_iterator begin(directory_iterator iter) noexcept;
|
||||
// directory_iterator end(directory_iterator iter) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#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 std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(directory_iterator_begin_end_tests)
|
||||
|
||||
TEST_CASE(test_function_signatures)
|
||||
{
|
||||
using D = directory_iterator;
|
||||
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()
|
@ -0,0 +1,38 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class directory_iterator
|
||||
|
||||
// typedef ... value_type;
|
||||
// typedef ... difference_type;
|
||||
// typedef ... pointer;
|
||||
// typedef ... reference;
|
||||
// typedef ... iterator_category
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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);
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class file_status
|
||||
|
||||
// explicit file_status() noexcept;
|
||||
// explicit file_status(file_type, perms prms = perms::unknown) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_convertible.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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 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);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class file_status
|
||||
|
||||
// void type(file_type) noexcept;
|
||||
// void permissions(perms) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class file_status
|
||||
|
||||
// file_type type() const noexcept;
|
||||
// perms permissions(p) const noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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() {
|
||||
static_assert(std::is_base_of<std::system_error, fs::filesystem_error>::value, "");
|
||||
test_constructors();
|
||||
test_signatures();
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// template <class Source>
|
||||
// path(const Source& source);
|
||||
// template <class InputIterator>
|
||||
// path(InputIterator first, InputIterator last);
|
||||
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
|
||||
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(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), mkRev(std::end(expect)), mkRev(std::begin(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(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), mkRev(std::end(expect)), mkRev(std::begin(expect))));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
using namespace fs;
|
||||
checkIteratorConcepts();
|
||||
checkBeginEndBasic(); // See path.decompose.pass.cpp for more tests.
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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("p1/p2")}
|
||||
, {S("p1/"), S("/p2"), S("p1//p2")}
|
||||
, {S("p1"), S("\\p2"), S("p1/\\p2")}
|
||||
, {S("p1\\"), S("p2"), S("p1\\/p2")}
|
||||
, {S("p1\\"), S("\\p2"), S("p1\\/\\p2")}
|
||||
, {S("p1"), S(""), S("p1")}
|
||||
, {S(""), S("p2"), S("p2")}
|
||||
};
|
||||
|
||||
|
||||
const AppendOperatorTestcase LongLHSCases[] =
|
||||
{
|
||||
{S("p1"), S("p2"), S("p1/p2")}
|
||||
, {S("p1/"), S("p2"), S("p1/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 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(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.append(RHS, StrEnd(RHS));
|
||||
}
|
||||
assert(LHS == E);
|
||||
}
|
||||
// input iterator - For non-native char types, appends needs to copy the
|
||||
// iterator range into a contigious 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.append(RHS, REnd);
|
||||
}
|
||||
assert(LHS == E);
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void doAppendSourceTest(AppendOperatorTestcase const& TC)
|
||||
{
|
||||
using namespace fs;
|
||||
using Ptr = CharT const*;
|
||||
using Str = std::basic_string<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.append(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.append(RHS);
|
||||
assert(LHS == E);
|
||||
assert(&Ref == &LHS);
|
||||
}
|
||||
{
|
||||
path LHS(L);
|
||||
Ptr RHS(R);
|
||||
path& Ref = LHS.append(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.append(RHS);
|
||||
assert(LHS == E);
|
||||
assert(&Ref == &LHS);
|
||||
}
|
||||
{
|
||||
path LHS(L);
|
||||
InputIter RHS(R);
|
||||
InputIter REnd(StrEnd(R));
|
||||
path& Ref = LHS.append(RHS, REnd);
|
||||
assert(LHS == E);
|
||||
assert(&Ref == &LHS);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path& operator=(path const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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);
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path& operator=(path&&) noexcept
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "count_new.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// template <class Source>
|
||||
// path& operator=(Source const&);
|
||||
// template <class Source>
|
||||
// path& assign(Source const&);
|
||||
// template <class InputIterator>
|
||||
// path& assign(InputIterator first, InputIterator last);
|
||||
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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 contigious 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);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Char* pointers
|
||||
{
|
||||
path p; PathReserve(p, Size + 1);
|
||||
{
|
||||
// char* pointers are contigious 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);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
for (auto const& MS : PathList) {
|
||||
RunTestCase<char>(MS);
|
||||
RunTestCase<wchar_t>(MS);
|
||||
RunTestCase<char16_t>(MS);
|
||||
RunTestCase<char32_t>(MS);
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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/.", 0},
|
||||
{"a/b//////", "a/b/////.", 0},
|
||||
{"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
|
||||
{"//" LONGA "////" LONGB "/" LONGC "///" LONGD, "//" LONGA "/" LONGB "/" LONGC "/" LONGD, 0},
|
||||
{ LONGA "/" LONGB "/" LONGC, LONGA "/" LONGB "/" LONGB, 1}
|
||||
|
||||
};
|
||||
#undef LONGA
|
||||
#undef LONGB
|
||||
#undef LONGC
|
||||
#undef LONGD
|
||||
|
||||
int main()
|
||||
{
|
||||
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 int E = TC.expect;
|
||||
{ // compare(...) functions
|
||||
DisableAllocationGuard g; // none of these operations should allocate
|
||||
|
||||
// check runtime results
|
||||
int ret1 = p1.compare(p2);
|
||||
int ret2 = p1.compare(R);
|
||||
int ret3 = p1.compare(TC.RHS);
|
||||
assert(ret1 == ret2 && ret1 == ret3);
|
||||
int normalized_ret = ret1 < 0 ? -1 : (ret1 > 0 ? 1 : 0);
|
||||
assert(normalized_ret == E);
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,277 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path& operator+=(const path& x);
|
||||
// path& operator+=(const string_type& x); // Implemented as Source template
|
||||
// path& operator+=(const value_type* x); // Implemented as Source template
|
||||
// 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 <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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 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);
|
||||
}
|
||||
// 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 contigious 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 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);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path(path const&)
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path() noexcept
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
using namespace fs;
|
||||
static_assert(std::is_nothrow_default_constructible<path>::value, "");
|
||||
const path p;
|
||||
assert(p.empty());
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path(path&&) noexcept
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "count_new.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// template <class Source>
|
||||
// path(const Source& source);
|
||||
// template <class InputIterator>
|
||||
// path(InputIterator first, InputIterator last);
|
||||
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "min_allocator.h"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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);
|
||||
// StringTypes
|
||||
{
|
||||
const std::basic_string<CharT> S(TestPath);
|
||||
path p(S);
|
||||
assert(p.native() == Expect);
|
||||
assert(p.string<CharT>() == TestPath);
|
||||
assert(p.string<CharT>() == S);
|
||||
}
|
||||
// Char* pointers
|
||||
{
|
||||
path p(TestPath);
|
||||
assert(p.native() == Expect);
|
||||
assert(p.string<CharT>() == TestPath);
|
||||
}
|
||||
{
|
||||
path p(TestPath, TestPathEnd);
|
||||
assert(p.native() == Expect);
|
||||
assert(p.string<CharT>() == TestPath);
|
||||
}
|
||||
// Iterators
|
||||
{
|
||||
using It = input_iterator<const CharT*>;
|
||||
path p(It{TestPath});
|
||||
assert(p.native() == Expect);
|
||||
assert(p.string<CharT>() == TestPath);
|
||||
}
|
||||
{
|
||||
using It = input_iterator<const CharT*>;
|
||||
path p(It{TestPath}, It{TestPathEnd});
|
||||
assert(p.native() == Expect);
|
||||
assert(p.string<CharT>() == TestPath);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
for (auto const& MS : PathList) {
|
||||
RunTestCase<char>(MS);
|
||||
RunTestCase<wchar_t>(MS);
|
||||
RunTestCase<char16_t>(MS);
|
||||
RunTestCase<char32_t>(MS);
|
||||
}
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
template <class It>
|
||||
std::reverse_iterator<It> mkRev(It it) {
|
||||
return std::reverse_iterator<It>(it);
|
||||
}
|
||||
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
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"}
|
||||
, {"//net/foo", {"//net", "/", "foo"}, "//net/", "//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) {
|
||||
path p(TC.raw);
|
||||
assert(p == TC.raw);
|
||||
|
||||
assert(p.root_path() == TC.root_path);
|
||||
assert(p.has_root_path() != TC.root_path.empty());
|
||||
|
||||
assert(p.root_name() == TC.root_name);
|
||||
assert(p.has_root_name() != TC.root_name.empty());
|
||||
|
||||
assert(p.root_directory() == TC.root_directory);
|
||||
assert(p.has_root_directory() != TC.root_directory.empty());
|
||||
|
||||
assert(p.relative_path() == TC.relative_path);
|
||||
assert(p.has_relative_path() != TC.relative_path.empty());
|
||||
|
||||
assert(p.parent_path() == TC.parent_path);
|
||||
assert(p.has_parent_path() != TC.parent_path.empty());
|
||||
|
||||
assert(p.filename() == TC.filename);
|
||||
assert(p.has_filename() != TC.filename.empty());
|
||||
|
||||
assert(p.is_absolute() == p.has_root_directory());
|
||||
assert(p.is_relative() != p.is_absolute());
|
||||
|
||||
assert(checkCollectionsEqual(p.begin(), p.end(),
|
||||
TC.elements.begin(), TC.elements.end()));
|
||||
// check backwards
|
||||
assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()),
|
||||
TC.elements.rbegin(), TC.elements.rend()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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"}
|
||||
};
|
||||
|
||||
|
||||
void decompFilenameTest()
|
||||
{
|
||||
using namespace fs;
|
||||
for (auto const & TC : FilenameTestCases) {
|
||||
path p(TC.raw);
|
||||
assert(p == TC.raw);
|
||||
|
||||
assert(p.filename() == TC.filename);
|
||||
assert(p.has_filename() != TC.filename.empty());
|
||||
|
||||
assert(p.stem() == TC.stem);
|
||||
assert(p.has_stem() != TC.stem.empty());
|
||||
|
||||
assert(p.extension() == TC.extension);
|
||||
assert(p.has_extension() != TC.extension.empty());
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
decompPathTest();
|
||||
decompFilenameTest();
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#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"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#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"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// void clear() noexcept
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
using namespace fs;
|
||||
const path p("/foo/bar/baz");
|
||||
{
|
||||
path p;
|
||||
ASSERT_NOEXCEPT(p.clear());
|
||||
ASSERT_SAME_TYPE(void, decltype(p.clear()));
|
||||
p.clear();
|
||||
assert(p.empty());
|
||||
}
|
||||
{
|
||||
path p2(p);
|
||||
assert(p == p2);
|
||||
p2.clear();
|
||||
assert(p2.empty());
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path& make_preferred()
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
struct MakePreferredTestcase {
|
||||
const char* value;
|
||||
};
|
||||
|
||||
const MakePreferredTestcase TestCases[] =
|
||||
{
|
||||
{""}
|
||||
, {"hello_world"}
|
||||
, {"/"}
|
||||
, {"/foo/bar/baz/"}
|
||||
, {"\\"}
|
||||
, {"\\foo\\bar\\baz\\"}
|
||||
, {"\\foo\\/bar\\/baz\\"}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path& remove_filename()
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
struct RemoveFilenameTestcase {
|
||||
const char* value;
|
||||
const char* expect;
|
||||
};
|
||||
|
||||
const RemoveFilenameTestcase TestCases[] =
|
||||
{
|
||||
{"", ""}
|
||||
, {"/", ""}
|
||||
, {"\\", ""}
|
||||
, {".", ""}
|
||||
, {"..", ""}
|
||||
, {"/foo", "/"}
|
||||
, {"/foo/", "/foo"}
|
||||
, {"/foo/.", "/foo"}
|
||||
, {"/foo/..", "/foo"}
|
||||
, {"/foo/////", "/foo"}
|
||||
, {"/foo\\\\", "/"}
|
||||
, {"/foo//\\/", "/foo//\\"}
|
||||
, {"file.txt", ""}
|
||||
, {"bar/../baz/./file.txt", "bar/../baz/."}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
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(p == TC.expect);
|
||||
assert(&Ref == &p);
|
||||
{
|
||||
const path parentp = p_orig.parent_path();
|
||||
if (parentp == p_orig.root_name()) {
|
||||
|
||||
assert(p.empty());
|
||||
} else {
|
||||
assert(p == parentp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path& replace_extension(path const& p = path())
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// path& replace_filename()
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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()
|
||||
{
|
||||
using namespace fs;
|
||||
for (auto const & TC : TestCases) {
|
||||
path p(TC.value);
|
||||
assert(p == TC.value);
|
||||
path& Ref = (p.replace_filename(TC.filename));
|
||||
assert(p == TC.expect);
|
||||
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(p2 == p);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// void swap(path& rhs) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// const value_type* c_str() const noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace fs;
|
||||
const char* const value = "hello world";
|
||||
const std::string str_value = value;
|
||||
path p(value);
|
||||
{ // Check signature
|
||||
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());
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// std::string string() const;
|
||||
// std::wstring wstring() const;
|
||||
// std::u8string u8string() const;
|
||||
// std::u16string u16string() const;
|
||||
// std::u32string u32string() const;
|
||||
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#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"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// const string_type& native() const noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace fs;
|
||||
const char* const value = "hello world";
|
||||
path p(value);
|
||||
{ // Check signature
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// operator string_type() const;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace fs;
|
||||
using string_type = path::string_type;
|
||||
const char* const value = "hello world";
|
||||
path p(value);
|
||||
{ // Check signature
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#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"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
MultiStringType shortString = MKSTR("abc");
|
||||
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; // should not allocate
|
||||
Str s = p.string<CharT>();
|
||||
assert(s == value);
|
||||
Str s2 = p.string<CharT>(Alloc{});
|
||||
assert(s2 == value);
|
||||
}
|
||||
}
|
||||
|
||||
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>;
|
||||
RequireAllocationGuard g; // should not allocate because
|
||||
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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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() {}
|
@ -0,0 +1,33 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// path operator/(path const&, path const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
// This is mainly tested via the member append functions.
|
||||
int main()
|
||||
{
|
||||
using namespace fs;
|
||||
path p1("abc");
|
||||
path p2("def");
|
||||
path p3 = p1 / p2;
|
||||
assert(p3 == "abc/def");
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// 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() {}
|
@ -0,0 +1,14 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// 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() {}
|
@ -0,0 +1,53 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// template <class Source>
|
||||
// path u8path(Source const&);
|
||||
// template <class InputIter>
|
||||
// path u8path(InputIter, InputIter);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#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() {
|
||||
doIOTest<char>();
|
||||
doIOTest<wchar_t>();
|
||||
//doIOTest<char16_t>();
|
||||
//doIOTest<char32_t>();
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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 <experimental/filesystem>
|
||||
#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() {
|
||||
doIOTest<char16_t>();
|
||||
doIOTest<char32_t>();
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// void swap(path& lhs, path& rhs) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "count_new.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
// NOTE: this is tested in path.members/path.modifiers via the member swap.
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class path
|
||||
|
||||
// typedef ... value_type;
|
||||
// typedef basic_string<value_type> string_type;
|
||||
// static constexpr value_type preferred_separator = ...;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
int main() {
|
||||
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 it's address.
|
||||
const char* dummy = &path::preferred_separator;
|
||||
((void)dummy);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// recursive_recursive_directory_iterator(recursive_recursive_directory_iterator const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,158 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// recursive_directory_iterator& operator=(recursive_directory_iterator const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,240 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/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) noexcept;
|
||||
// recursive_directory_iterator(const path& p, directory_options options, error_code& ec) noexcept;
|
||||
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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&) noexcept
|
||||
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&) noexcept
|
||||
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 std::experimental::filesystem;
|
||||
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 std::experimental::filesystem;
|
||||
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()
|
@ -0,0 +1,66 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// int depth() const
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,43 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// void disable_recursion_pending();
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,228 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// recursive_directory_iterator& operator++();
|
||||
// recursive_directory_iterator& increment(error_code& ec) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#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 std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(recursive_directory_iterator_increment_tests)
|
||||
|
||||
TEST_CASE(test_increment_signatures)
|
||||
{
|
||||
using D = recursive_directory_iterator;
|
||||
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_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 std::experimental::filesystem;
|
||||
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];
|
||||
|
||||
// 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;
|
||||
recursive_directory_iterator it(startDir, ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_REQUIRE(it != endIt);
|
||||
const path elem = *it;
|
||||
TEST_REQUIRE(elem == permDeniedDir);
|
||||
|
||||
it.increment(ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_REQUIRE(it == endIt);
|
||||
}
|
||||
// Same as obove but test operator++().
|
||||
{
|
||||
std::error_code ec;
|
||||
recursive_directory_iterator it(startDir, ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_REQUIRE(it != endIt);
|
||||
const path elem = *it;
|
||||
TEST_REQUIRE(elem == 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;
|
||||
recursive_directory_iterator it(
|
||||
startDir,directory_options::skip_permission_denied,
|
||||
ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_REQUIRE(it != endIt);
|
||||
const path elem = *it;
|
||||
TEST_REQUIRE(elem == permDeniedDir);
|
||||
|
||||
it.increment(ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_REQUIRE(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 obove 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;
|
||||
recursive_directory_iterator it(permDeniedDir,
|
||||
directory_options::skip_permission_denied,
|
||||
ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_REQUIRE(it == endIt);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END()
|
@ -0,0 +1,80 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// recursive_directory_iterator(recursive_directory_iterator&&) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,163 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// recursive_directory_iterator& operator=(recursive_directory_iterator const&);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
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()
|
@ -0,0 +1,93 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// void pop();
|
||||
// void pop(error_code& ec);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(recursive_directory_iterator_pop_tests)
|
||||
|
||||
TEST_CASE(signature_tests)
|
||||
{
|
||||
recursive_directory_iterator it{}; ((void)it);
|
||||
std::error_code ec; ((void)ec);
|
||||
ASSERT_NOT_NOEXCEPT(it.pop());
|
||||
ASSERT_NOT_NOEXCEPT(it.pop(ec)); // may require allocation or other things
|
||||
}
|
||||
|
||||
// NOTE: Since the order of iteration is unspecified we use a list of
|
||||
// seen files at each depth to determine the new depth after a 'pop()' operation.
|
||||
TEST_CASE(test_depth)
|
||||
{
|
||||
const recursive_directory_iterator endIt{};
|
||||
|
||||
auto& DE0 = StaticEnv::DirIterationList;
|
||||
std::set<path> notSeenDepth0(std::begin(DE0), std::end(DE0));
|
||||
|
||||
auto& DE1 = StaticEnv::DirIterationListDepth1;
|
||||
std::set<path> notSeenDepth1(std::begin(DE1), std::end(DE1));
|
||||
|
||||
std::error_code ec;
|
||||
recursive_directory_iterator it(StaticEnv::Dir, ec);
|
||||
TEST_REQUIRE(it != endIt);
|
||||
TEST_CHECK(it.depth() == 0);
|
||||
|
||||
while (it.depth() != 2) {
|
||||
if (it.depth() == 0)
|
||||
notSeenDepth0.erase(it->path());
|
||||
else
|
||||
notSeenDepth1.erase(it->path());
|
||||
++it;
|
||||
TEST_REQUIRE(it != endIt);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto set_ec = std::make_error_code(std::errc::address_in_use);
|
||||
it.pop(set_ec);
|
||||
TEST_REQUIRE(!set_ec);
|
||||
|
||||
if (it == endIt) {
|
||||
// We must have seen every entry at depth 0 and 1.
|
||||
TEST_REQUIRE(notSeenDepth0.empty() && notSeenDepth1.empty());
|
||||
break;
|
||||
}
|
||||
else if (it.depth() == 1) {
|
||||
// If we popped to depth 1 then there must be unseen entries
|
||||
// at this level.
|
||||
TEST_REQUIRE(!notSeenDepth1.empty());
|
||||
TEST_CHECK(notSeenDepth1.count(it->path()));
|
||||
notSeenDepth1.clear();
|
||||
}
|
||||
else if (it.depth() == 0) {
|
||||
// If we popped to depth 0 there must be unseen entries at this
|
||||
// level. There should also be no unseen entries at depth 1.
|
||||
TEST_REQUIRE(!notSeenDepth0.empty());
|
||||
TEST_REQUIRE(notSeenDepth1.empty());
|
||||
TEST_CHECK(notSeenDepth0.count(it->path()));
|
||||
notSeenDepth0.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END()
|
@ -0,0 +1,145 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// bool recursion_pending() const;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(recursive_directory_iterator_recursion_pending_tests)
|
||||
|
||||
TEST_CASE(initial_value_test)
|
||||
{
|
||||
recursive_directory_iterator it(StaticEnv::Dir);
|
||||
TEST_REQUIRE(it.recursion_pending() == true);
|
||||
}
|
||||
|
||||
TEST_CASE(value_after_copy_construction_and_assignment_test)
|
||||
{
|
||||
recursive_directory_iterator rec_pending_it(StaticEnv::Dir);
|
||||
recursive_directory_iterator no_rec_pending_it(StaticEnv::Dir);
|
||||
no_rec_pending_it.disable_recursion_pending();
|
||||
|
||||
{ // copy construction
|
||||
recursive_directory_iterator it(rec_pending_it);
|
||||
TEST_CHECK(it.recursion_pending() == true);
|
||||
it.disable_recursion_pending();
|
||||
TEST_REQUIRE(rec_pending_it.recursion_pending() == true);
|
||||
|
||||
recursive_directory_iterator it2(no_rec_pending_it);
|
||||
TEST_CHECK(it2.recursion_pending() == false);
|
||||
}
|
||||
{ // copy assignment
|
||||
recursive_directory_iterator it(StaticEnv::Dir);
|
||||
it.disable_recursion_pending();
|
||||
it = rec_pending_it;
|
||||
TEST_CHECK(it.recursion_pending() == true);
|
||||
it.disable_recursion_pending();
|
||||
TEST_REQUIRE(rec_pending_it.recursion_pending() == true);
|
||||
|
||||
recursive_directory_iterator it2(StaticEnv::Dir);
|
||||
it2 = no_rec_pending_it;
|
||||
TEST_CHECK(it2.recursion_pending() == false);
|
||||
}
|
||||
TEST_CHECK(rec_pending_it.recursion_pending() == true);
|
||||
TEST_CHECK(no_rec_pending_it.recursion_pending() == false);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE(value_after_move_construction_and_assignment_test)
|
||||
{
|
||||
recursive_directory_iterator rec_pending_it(StaticEnv::Dir);
|
||||
recursive_directory_iterator no_rec_pending_it(StaticEnv::Dir);
|
||||
no_rec_pending_it.disable_recursion_pending();
|
||||
|
||||
{ // move construction
|
||||
recursive_directory_iterator it_cp(rec_pending_it);
|
||||
recursive_directory_iterator it(std::move(it_cp));
|
||||
TEST_CHECK(it.recursion_pending() == true);
|
||||
|
||||
recursive_directory_iterator it_cp2(no_rec_pending_it);
|
||||
recursive_directory_iterator it2(std::move(it_cp2));
|
||||
TEST_CHECK(it2.recursion_pending() == false);
|
||||
}
|
||||
{ // copy assignment
|
||||
recursive_directory_iterator it(StaticEnv::Dir);
|
||||
it.disable_recursion_pending();
|
||||
recursive_directory_iterator it_cp(rec_pending_it);
|
||||
it = std::move(it_cp);
|
||||
TEST_CHECK(it.recursion_pending() == true);
|
||||
|
||||
recursive_directory_iterator it2(StaticEnv::Dir);
|
||||
recursive_directory_iterator it_cp2(no_rec_pending_it);
|
||||
it2 = std::move(it_cp2);
|
||||
TEST_CHECK(it2.recursion_pending() == false);
|
||||
}
|
||||
TEST_CHECK(rec_pending_it.recursion_pending() == true);
|
||||
TEST_CHECK(no_rec_pending_it.recursion_pending() == false);
|
||||
}
|
||||
|
||||
TEST_CASE(increment_resets_value)
|
||||
{
|
||||
const recursive_directory_iterator endIt;
|
||||
{
|
||||
recursive_directory_iterator it(StaticEnv::Dir);
|
||||
it.disable_recursion_pending();
|
||||
TEST_CHECK(it.recursion_pending() == false);
|
||||
++it;
|
||||
TEST_CHECK(it.recursion_pending() == true);
|
||||
TEST_CHECK(it.depth() == 0);
|
||||
}
|
||||
{
|
||||
recursive_directory_iterator it(StaticEnv::Dir);
|
||||
it.disable_recursion_pending();
|
||||
TEST_CHECK(it.recursion_pending() == false);
|
||||
it++;
|
||||
TEST_CHECK(it.recursion_pending() == true);
|
||||
TEST_CHECK(it.depth() == 0);
|
||||
}
|
||||
{
|
||||
recursive_directory_iterator it(StaticEnv::Dir);
|
||||
it.disable_recursion_pending();
|
||||
TEST_CHECK(it.recursion_pending() == false);
|
||||
std::error_code ec;
|
||||
it.increment(ec);
|
||||
TEST_CHECK(it.recursion_pending() == true);
|
||||
TEST_CHECK(it.depth() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(pop_does_not_reset_value)
|
||||
{
|
||||
const recursive_directory_iterator endIt;
|
||||
recursive_directory_iterator it(StaticEnv::Dir);
|
||||
|
||||
while (it.depth() == 0) {
|
||||
++it;
|
||||
TEST_REQUIRE(it != endIt);
|
||||
}
|
||||
it.disable_recursion_pending();
|
||||
it.pop();
|
||||
TEST_REQUIRE(it != endIt);
|
||||
TEST_CHECK(it.recursion_pending() == false);
|
||||
}
|
||||
|
||||
TEST_SUITE_END()
|
@ -0,0 +1,61 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// class recursive_directory_iterator
|
||||
|
||||
// recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
|
||||
// recursive_directory_iterator end(recursive_directory_iterator iter) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#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 std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(recursive_directory_iterator_begin_end_tests)
|
||||
|
||||
TEST_CASE(test_function_signatures)
|
||||
{
|
||||
using D = recursive_directory_iterator;
|
||||
recursive_directory_iterator d; ((void)d);
|
||||
|
||||
ASSERT_SAME_TYPE(decltype(begin(d)), recursive_directory_iterator);
|
||||
ASSERT_NOEXCEPT(begin(std::move(d)));
|
||||
|
||||
ASSERT_SAME_TYPE(decltype(end(d)), recursive_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::RecDirIterationList),
|
||||
std::end( StaticEnv::RecDirIterationList));
|
||||
|
||||
std::error_code ec;
|
||||
recursive_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()
|
@ -0,0 +1,75 @@
|
||||
#ifndef TEST_BITMASK_TYPE_HPP
|
||||
#define TEST_BITMASK_TYPE_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
|
||||
template <class EnumType, EnumType Val1, EnumType Val2,
|
||||
class UT = typename std::underlying_type<EnumType>::type,
|
||||
UT UVal1 = static_cast<UT>(Val1),
|
||||
UT UVal2 = static_cast<UT>(Val2),
|
||||
UT UZero = static_cast<UT>(0),
|
||||
EnumType Zero = static_cast<EnumType>(0)
|
||||
>
|
||||
struct check_bitmask_type {
|
||||
|
||||
static constexpr UT dcast(EnumType e) { return static_cast<UT>(e); }
|
||||
static constexpr UT unpromote(decltype(~UZero) promoted) { return static_cast<UT>(promoted); }
|
||||
// We need two values that are non-zero and share at least one bit.
|
||||
static_assert(Val1 != Zero && Val2 != Zero, "");
|
||||
static_assert(Val1 != Val2, "");
|
||||
static_assert((UVal1 & UVal2) == 0, "");
|
||||
|
||||
|
||||
static bool check()
|
||||
{
|
||||
{
|
||||
EnumType ValRef = Val1;
|
||||
ASSERT_SAME_TYPE(EnumType, decltype(Val1 & Val2));
|
||||
ASSERT_SAME_TYPE(EnumType, decltype(Val1 | Val2));
|
||||
ASSERT_SAME_TYPE(EnumType, decltype(Val1 ^ Val2));
|
||||
ASSERT_SAME_TYPE(EnumType, decltype(~Val1));
|
||||
ASSERT_SAME_TYPE(EnumType&, decltype(ValRef &= Val2));
|
||||
ASSERT_SAME_TYPE(EnumType&, decltype(ValRef |= Val2));
|
||||
ASSERT_SAME_TYPE(EnumType&, decltype(ValRef ^= Val2));
|
||||
}
|
||||
|
||||
static_assert((Val1 & Zero) == Zero, "");
|
||||
static_assert((Val1 & Val1) == Val1, "");
|
||||
static_assert(dcast(Val1 & Val2) == (UVal1 & UVal2), "");
|
||||
|
||||
static_assert((Val1 | Zero) == Val1, "");
|
||||
static_assert(dcast(Val1 | Val2) == (UVal1 | UVal2), "");
|
||||
|
||||
static_assert((Val1 ^ Zero) == Val1, "");
|
||||
static_assert(dcast(Val1 ^ Val2) == (UVal1 ^ UVal2), "");
|
||||
|
||||
static_assert(dcast(~Zero) == unpromote(~UZero), "");
|
||||
static_assert(dcast(~Val1) == unpromote(~UVal1), "");
|
||||
|
||||
{
|
||||
EnumType e = Val1;
|
||||
EnumType& eref = (e &= Val2);
|
||||
assert(&eref == &e);
|
||||
assert(dcast(eref) == (UVal1 & UVal2));
|
||||
}
|
||||
{
|
||||
EnumType e = Val1;
|
||||
EnumType& eref = (e |= Val2);
|
||||
assert(&eref == &e);
|
||||
assert(dcast(eref) == (UVal1 | UVal2));
|
||||
}
|
||||
{
|
||||
EnumType e = Val1;
|
||||
EnumType& eref = (e ^= Val2);
|
||||
assert(&eref == &e);
|
||||
assert(dcast(eref) == (UVal1 ^ UVal2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TEST_BITMASK_TYPE
|
@ -0,0 +1,64 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// enum class copy_options;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "check_bitmask_types.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
constexpr fs::copy_options ME(int val) { return static_cast<fs::copy_options>(val); }
|
||||
|
||||
int main() {
|
||||
typedef fs::copy_options E;
|
||||
static_assert(std::is_enum<E>::value, "");
|
||||
|
||||
// Check that E is a scoped enum by checking for conversions.
|
||||
typedef std::underlying_type<E>::type UT;
|
||||
static_assert(!std::is_convertible<E, UT>::value, "");
|
||||
|
||||
static_assert(std::is_same<UT, unsigned short>::value, ""); // Implementation detail
|
||||
|
||||
typedef check_bitmask_type<E, E::skip_existing, E::update_existing> BitmaskTester;
|
||||
assert(BitmaskTester::check());
|
||||
|
||||
static_assert(
|
||||
E::none == ME(0),
|
||||
"Expected enumeration values do not match");
|
||||
// Option group for copy_file
|
||||
static_assert(
|
||||
E::skip_existing == ME(1) &&
|
||||
E::overwrite_existing == ME(2) &&
|
||||
E::update_existing == ME(4),
|
||||
"Expected enumeration values do not match");
|
||||
// Option group for copy on directories
|
||||
static_assert(
|
||||
E::recursive == ME(8),
|
||||
"Expected enumeration values do not match");
|
||||
// Option group for copy on symlinks
|
||||
static_assert(
|
||||
E::copy_symlinks == ME(16) &&
|
||||
E::skip_symlinks == ME(32),
|
||||
"Expected enumeration values do not match");
|
||||
// Option group for changing form of copy
|
||||
static_assert(
|
||||
E::directories_only == ME(64) &&
|
||||
E::create_symlinks == ME(128) &&
|
||||
E::create_hard_links == ME(256),
|
||||
"Expected enumeration values do not match");
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// enum class directory_options;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "check_bitmask_types.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
constexpr fs::directory_options ME(int val) { return static_cast<fs::directory_options>(val); }
|
||||
|
||||
int main() {
|
||||
typedef fs::directory_options E;
|
||||
static_assert(std::is_enum<E>::value, "");
|
||||
|
||||
// Check that E is a scoped enum by checking for conversions.
|
||||
typedef std::underlying_type<E>::type UT;
|
||||
static_assert(!std::is_convertible<E, UT>::value, "");
|
||||
static_assert(std::is_same<UT, unsigned char>::value, "");
|
||||
|
||||
typedef check_bitmask_type<E, E::follow_directory_symlink, E::skip_permission_denied> BitmaskTester;
|
||||
assert(BitmaskTester::check());
|
||||
|
||||
static_assert(
|
||||
E::none == ME(0) &&
|
||||
E::follow_directory_symlink == ME(1) &&
|
||||
E::skip_permission_denied == ME(2),
|
||||
"Expected enumeration values do not match");
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// enum class file_type;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
constexpr fs::file_type ME(int val) { return static_cast<fs::file_type>(val); }
|
||||
|
||||
int main() {
|
||||
typedef fs::file_type E;
|
||||
static_assert(std::is_enum<E>::value, "");
|
||||
|
||||
// Check that E is a scoped enum by checking for conversions.
|
||||
typedef std::underlying_type<E>::type UT;
|
||||
static_assert(!std::is_convertible<E, UT>::value, "");
|
||||
|
||||
static_assert(std::is_same<UT, signed char>::value, ""); // Implementation detail
|
||||
|
||||
static_assert(
|
||||
E::none == ME(0) &&
|
||||
E::not_found == ME(-1) &&
|
||||
E::regular == ME(1) &&
|
||||
E::directory == ME(2) &&
|
||||
E::symlink == ME(3) &&
|
||||
E::block == ME(4) &&
|
||||
E::character == ME(5) &&
|
||||
E::fifo == ME(6) &&
|
||||
E::socket == ME(7) &&
|
||||
E::unknown == ME(8),
|
||||
"Expected enumeration values do not match");
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// enum class perms;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "check_bitmask_types.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
constexpr fs::perms ME(int val) { return static_cast<fs::perms>(val); }
|
||||
|
||||
int main() {
|
||||
typedef fs::perms E;
|
||||
static_assert(std::is_enum<E>::value, "");
|
||||
|
||||
// Check that E is a scoped enum by checking for conversions.
|
||||
typedef std::underlying_type<E>::type UT;
|
||||
static_assert(!std::is_convertible<E, UT>::value, "");
|
||||
|
||||
static_assert(std::is_same<UT, unsigned >::value, ""); // Implementation detail
|
||||
|
||||
typedef check_bitmask_type<E, E::group_all, E::owner_all> BitmaskTester;
|
||||
assert(BitmaskTester::check());
|
||||
|
||||
static_assert(
|
||||
E::none == ME(0) &&
|
||||
|
||||
E::owner_read == ME(0400) &&
|
||||
E::owner_write == ME(0200) &&
|
||||
E::owner_exec == ME(0100) &&
|
||||
E::owner_all == ME(0700) &&
|
||||
|
||||
E::group_read == ME(040) &&
|
||||
E::group_write == ME(020) &&
|
||||
E::group_exec == ME(010) &&
|
||||
E::group_all == ME(070) &&
|
||||
|
||||
E::others_read == ME(04) &&
|
||||
E::others_write == ME(02) &&
|
||||
E::others_exec == ME(01) &&
|
||||
E::others_all == ME(07) &&
|
||||
E::all == ME(0777) &&
|
||||
E::set_uid == ME(04000) &&
|
||||
E::set_gid == ME(02000) &&
|
||||
E::sticky_bit == ME(01000) &&
|
||||
E::mask == ME(07777) &&
|
||||
E::unknown == ME(0xFFFF) &&
|
||||
E::add_perms == ME(0x10000) &&
|
||||
E::remove_perms == ME(0x20000) &&
|
||||
E::resolve_symlinks == ME(0x40000),
|
||||
"Expected enumeration values do not match");
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
int main()
|
||||
{
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// typedef TrivialClock file_time_type;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
|
||||
// system_clock is used because it meets the requirements of TrivialClock,
|
||||
// and it's resolution and range of system_clock should match the operating
|
||||
// systems file time type.
|
||||
typedef std::chrono::system_clock ExpectedClock;
|
||||
typedef std::chrono::time_point<ExpectedClock> ExpectedTimePoint;
|
||||
|
||||
int main() {
|
||||
static_assert(std::is_same<
|
||||
std::experimental::filesystem::file_time_type,
|
||||
ExpectedTimePoint
|
||||
>::value, "");
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// path absolute(const path& p, const path& base=current_path());
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(filesystem_absolute_path_test_suite)
|
||||
|
||||
TEST_CASE(absolute_signature_test)
|
||||
{
|
||||
const path p; ((void)p);
|
||||
ASSERT_NOT_NOEXCEPT(absolute(p));
|
||||
ASSERT_NOT_NOEXCEPT(absolute(p, p));
|
||||
}
|
||||
|
||||
// There are 4 cases is the proposal for absolute path.
|
||||
// Each scope tests one of the cases.
|
||||
TEST_CASE(absolute_path_test)
|
||||
{
|
||||
// has_root_name() && has_root_directory()
|
||||
{
|
||||
const path p("//net/foo");
|
||||
const path base("//net/bar/baz");
|
||||
TEST_REQUIRE(p.has_root_name());
|
||||
TEST_REQUIRE(p.has_root_directory());
|
||||
TEST_CHECK(p.is_absolute());
|
||||
path ret = absolute(p, base);
|
||||
TEST_CHECK(ret.is_absolute());
|
||||
TEST_CHECK(ret == p);
|
||||
}
|
||||
// !has_root_name() && has_root_directory()
|
||||
{
|
||||
const path p("/foo");
|
||||
const path base("//net/bar");
|
||||
TEST_REQUIRE(not p.has_root_name());
|
||||
TEST_REQUIRE(p.has_root_directory());
|
||||
TEST_CHECK(p.is_absolute());
|
||||
// ensure absolute(base) is not recursivly called
|
||||
TEST_REQUIRE(base.has_root_name());
|
||||
TEST_REQUIRE(base.has_root_directory());
|
||||
|
||||
path ret = absolute(p, base);
|
||||
TEST_CHECK(ret.is_absolute());
|
||||
TEST_CHECK(ret.has_root_name());
|
||||
TEST_CHECK(ret.root_name() == path("//net"));
|
||||
TEST_CHECK(ret.has_root_directory());
|
||||
TEST_CHECK(ret.root_directory() == path("/"));
|
||||
TEST_CHECK(ret == path("//net/foo"));
|
||||
}
|
||||
// has_root_name() && !has_root_directory()
|
||||
{
|
||||
const path p("//net");
|
||||
const path base("//net/foo/bar");
|
||||
TEST_REQUIRE(p.has_root_name());
|
||||
TEST_REQUIRE(not p.has_root_directory());
|
||||
TEST_CHECK(not p.is_absolute());
|
||||
// absolute is called recursivly on base. The following conditions
|
||||
// must be true for it to return base unmodified
|
||||
TEST_REQUIRE(base.has_root_name());
|
||||
TEST_REQUIRE(base.has_root_directory());
|
||||
path ret = absolute(p, base);
|
||||
const path expect("//net/foo/bar");
|
||||
TEST_CHECK(ret.is_absolute());
|
||||
TEST_CHECK(ret == path("//net/foo/bar"));
|
||||
}
|
||||
// !has_root_name() && !has_root_directory()
|
||||
{
|
||||
const path p("bar/baz");
|
||||
const path base("//net/foo");
|
||||
TEST_REQUIRE(not p.has_root_name());
|
||||
TEST_REQUIRE(not p.has_root_directory());
|
||||
TEST_REQUIRE(base.has_root_name());
|
||||
TEST_REQUIRE(base.has_root_directory());
|
||||
|
||||
path ret = absolute(p, base);
|
||||
TEST_CHECK(ret.is_absolute());
|
||||
TEST_CHECK(ret == path("//net/foo/bar/baz"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(absolute_path_with_default_base)
|
||||
{
|
||||
const path testCases[] = {
|
||||
"//net/foo", // has_root_name() && has_root_directory()
|
||||
"/foo", // !has_root_name() && has_root_directory()
|
||||
"//net", // has_root_name() && !has_root_directory()
|
||||
"bar/baz" // !has_root_name() && !has_root_directory()
|
||||
};
|
||||
const path base = current_path();
|
||||
for (auto& p : testCases) {
|
||||
const path ret = absolute(p);
|
||||
const path expect = absolute(p, base);
|
||||
TEST_CHECK(ret.is_absolute());
|
||||
TEST_CHECK(ret == expect);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END()
|
@ -0,0 +1,118 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// path canonical(const path& p, const path& base = current_path());
|
||||
// path canonical(const path& p, error_code& ec);
|
||||
// path canonical(const path& p, const path& base, error_code& ec);
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
TEST_SUITE(filesystem_canonical_path_test_suite)
|
||||
|
||||
TEST_CASE(signature_test)
|
||||
{
|
||||
const path p; ((void)p);
|
||||
std::error_code ec; ((void)ec);
|
||||
ASSERT_NOT_NOEXCEPT(canonical(p));
|
||||
ASSERT_NOT_NOEXCEPT(canonical(p, p));
|
||||
ASSERT_NOT_NOEXCEPT(canonical(p, ec));
|
||||
ASSERT_NOT_NOEXCEPT(canonical(p, p, ec));
|
||||
}
|
||||
|
||||
// There are 4 cases is the proposal for absolute path.
|
||||
// Each scope tests one of the cases.
|
||||
TEST_CASE(test_canonical)
|
||||
{
|
||||
// has_root_name() && has_root_directory()
|
||||
const path Root = StaticEnv::Root;
|
||||
const path RootName = Root.filename();
|
||||
const path DirName = StaticEnv::Dir.filename();
|
||||
const path SymlinkName = StaticEnv::SymlinkToFile.filename();
|
||||
struct TestCase {
|
||||
path p;
|
||||
path expect;
|
||||
path base = StaticEnv::Root;
|
||||
};
|
||||
const TestCase testCases[] = {
|
||||
{ ".", Root, Root},
|
||||
{ DirName / ".." / "." / DirName, StaticEnv::Dir, Root},
|
||||
{ StaticEnv::Dir2 / "..", StaticEnv::Dir },
|
||||
{ StaticEnv::Dir3 / "../..", StaticEnv::Dir },
|
||||
{ StaticEnv::Dir / ".", StaticEnv::Dir },
|
||||
{ Root / "." / DirName / ".." / DirName, StaticEnv::Dir},
|
||||
{ path("..") / "." / RootName / DirName / ".." / DirName, StaticEnv::Dir, Root},
|
||||
{ StaticEnv::SymlinkToFile, StaticEnv::File },
|
||||
{ SymlinkName, StaticEnv::File, StaticEnv::Root}
|
||||
};
|
||||
for (auto& TC : testCases) {
|
||||
std::error_code ec;
|
||||
const path ret = canonical(TC.p, TC.base, ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
const path ret2 = canonical(TC.p, TC.base);
|
||||
TEST_CHECK(ret == TC.expect);
|
||||
TEST_CHECK(ret == ret2);
|
||||
TEST_CHECK(ret.is_absolute());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(test_dne_path)
|
||||
{
|
||||
std::error_code ec;
|
||||
{
|
||||
const path ret = canonical(StaticEnv::DNE, ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_CHECK(ret == path{});
|
||||
}
|
||||
ec.clear();
|
||||
{
|
||||
const path ret = canonical(StaticEnv::DNE, StaticEnv::Root, ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_CHECK(ret == path{});
|
||||
}
|
||||
{
|
||||
TEST_CHECK_THROW(filesystem_error, canonical(StaticEnv::DNE));
|
||||
TEST_CHECK_THROW(filesystem_error, canonical(StaticEnv::DNE, StaticEnv::Root));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(test_exception_contains_paths)
|
||||
{
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
const path p = "blabla/dne";
|
||||
const path base = StaticEnv::Root;
|
||||
try {
|
||||
canonical(p, base);
|
||||
TEST_REQUIRE(false);
|
||||
} catch (filesystem_error const& err) {
|
||||
TEST_CHECK(err.path1() == p);
|
||||
TEST_CHECK(err.path2() == base);
|
||||
}
|
||||
try {
|
||||
canonical(p);
|
||||
TEST_REQUIRE(false);
|
||||
} catch (filesystem_error const& err) {
|
||||
TEST_CHECK(err.path1() == p);
|
||||
TEST_CHECK(err.path2() == current_path());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_SUITE_END()
|
@ -0,0 +1,251 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/filesystem>
|
||||
|
||||
// void copy(const path& from, const path& to);
|
||||
// void copy(const path& from, const path& to, error_code& ec) noexcept;
|
||||
// void copy(const path& from, const path& to, copy_options options);
|
||||
// void copy(const path& from, const path& to, copy_options options,
|
||||
// error_code& ec) noexcept;
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "rapid-cxx-test.hpp"
|
||||
#include "filesystem_test_helper.hpp"
|
||||
|
||||
using namespace std::experimental::filesystem;
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
using CO = fs::copy_options;
|
||||
|
||||
TEST_SUITE(filesystem_copy_test_suite)
|
||||
|
||||
TEST_CASE(signature_test)
|
||||
{
|
||||
const path p; ((void)p);
|
||||
std::error_code ec; ((void)ec);
|
||||
const copy_options opts{}; ((void)opts);
|
||||
ASSERT_NOT_NOEXCEPT(fs::copy(p, p));
|
||||
ASSERT_NOEXCEPT(fs::copy(p, p, ec));
|
||||
ASSERT_NOT_NOEXCEPT(copy(p, p, opts));
|
||||
ASSERT_NOEXCEPT(copy(p, p, opts, ec));
|
||||
}
|
||||
|
||||
// There are 4 cases is the proposal for absolute path.
|
||||
// Each scope tests one of the cases.
|
||||
TEST_CASE(test_error_reporting)
|
||||
{
|
||||
auto checkThrow = [](path const& f, path const& t, const std::error_code& ec)
|
||||
{
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
try {
|
||||
fs::copy(f, t);
|
||||
return false;
|
||||
} catch (filesystem_error const& err) {
|
||||
return err.path1() == f
|
||||
&& err.path2() == t
|
||||
&& err.code() == ec;
|
||||
}
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
};
|
||||
|
||||
scoped_test_env env;
|
||||
const path file = env.create_file("file1", 42);
|
||||
const path dir = env.create_dir("dir");
|
||||
const path fifo = env.create_fifo("fifo");
|
||||
TEST_REQUIRE(is_other(fifo));
|
||||
|
||||
// !exists(f)
|
||||
{
|
||||
std::error_code ec;
|
||||
const path f = StaticEnv::DNE;
|
||||
const path t = env.test_root;
|
||||
fs::copy(f, t, ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_CHECK(checkThrow(f, t, ec));
|
||||
}
|
||||
{ // equivalent(f, t) == true
|
||||
std::error_code ec;
|
||||
fs::copy(file, file, ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_CHECK(checkThrow(file, file, ec));
|
||||
}
|
||||
{ // is_directory(from) && is_file(to)
|
||||
std::error_code ec;
|
||||
fs::copy(dir, file, ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_CHECK(checkThrow(dir, file, ec));
|
||||
}
|
||||
{ // is_other(from)
|
||||
std::error_code ec;
|
||||
fs::copy(fifo, dir, ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_CHECK(checkThrow(fifo, dir, ec));
|
||||
}
|
||||
{ // is_other(to)
|
||||
std::error_code ec;
|
||||
fs::copy(file, fifo, ec);
|
||||
TEST_REQUIRE(ec);
|
||||
TEST_CHECK(checkThrow(file, fifo, ec));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(from_is_symlink)
|
||||
{
|
||||
scoped_test_env env;
|
||||
const path file = env.create_file("file", 42);
|
||||
const path symlink = env.create_symlink(file, "sym");
|
||||
const path dne = env.make_env_path("dne");
|
||||
|
||||
{ // skip symlinks
|
||||
std::error_code ec;
|
||||
fs::copy(symlink, dne, copy_options::skip_symlinks, ec);
|
||||
TEST_CHECK(!ec);
|
||||
TEST_CHECK(!exists(dne));
|
||||
}
|
||||
{
|
||||
const path dest = env.make_env_path("dest");
|
||||
std::error_code ec;
|
||||
fs::copy(symlink, dest, copy_options::copy_symlinks, ec);
|
||||
TEST_CHECK(!ec);
|
||||
TEST_CHECK(exists(dest));
|
||||
TEST_CHECK(is_symlink(dest));
|
||||
}
|
||||
{ // copy symlink but target exists
|
||||
std::error_code ec;
|
||||
fs::copy(symlink, file, copy_options::copy_symlinks, ec);
|
||||
TEST_CHECK(ec);
|
||||
}
|
||||
{ // create symlinks but target exists
|
||||
std::error_code ec;
|
||||
fs::copy(symlink, file, copy_options::create_symlinks, ec);
|
||||
TEST_CHECK(ec);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(from_is_regular_file)
|
||||
{
|
||||
scoped_test_env env;
|
||||
const path file = env.create_file("file", 42);
|
||||
const path dir = env.create_dir("dir");
|
||||
{ // skip copy because of directory
|
||||
const path dest = env.make_env_path("dest1");
|
||||
std::error_code ec;
|
||||
fs::copy(file, dest, CO::directories_only, ec);
|
||||
TEST_CHECK(!ec);
|
||||
TEST_CHECK(!exists(dest));
|
||||
}
|
||||
{ // create symlink to file
|
||||
const path dest = env.make_env_path("sym");
|
||||
std::error_code ec;
|
||||
fs::copy(file, dest, CO::create_symlinks, ec);
|
||||
TEST_CHECK(!ec);
|
||||
TEST_CHECK(is_symlink(dest));
|
||||
TEST_CHECK(equivalent(file, canonical(dest)));
|
||||
}
|
||||
{ // create hard link to file
|
||||
const path dest = env.make_env_path("hardlink");
|
||||
TEST_CHECK(hard_link_count(file) == 1);
|
||||
std::error_code ec;
|
||||
fs::copy(file, dest, CO::create_hard_links, ec);
|
||||
TEST_CHECK(!ec);
|
||||
TEST_CHECK(exists(dest));
|
||||
TEST_CHECK(hard_link_count(file) == 2);
|
||||
}
|
||||
{ // is_directory(t)
|
||||
const path dest_dir = env.create_dir("dest_dir");
|
||||
const path expect_dest = dest_dir / file.filename();
|
||||
std::error_code ec;
|
||||
fs::copy(file, dest_dir, ec);
|
||||
TEST_CHECK(!ec);
|
||||
TEST_CHECK(is_regular_file(expect_dest));
|
||||
}
|
||||
{ // otherwise copy_file(from, to, ...)
|
||||
const path dest = env.make_env_path("file_copy");
|
||||
std::error_code ec;
|
||||
fs::copy(file, dest, ec);
|
||||
TEST_CHECK(!ec);
|
||||
TEST_CHECK(is_regular_file(dest));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(from_is_directory)
|
||||
{
|
||||
struct FileInfo {
|
||||
path filename;
|
||||
int size;
|
||||
};
|
||||
const FileInfo files[] = {
|
||||
{"file1", 0},
|
||||
{"file2", 42},
|
||||
{"file3", 300}
|
||||
};
|
||||
scoped_test_env env;
|
||||
const path dir = env.create_dir("dir");
|
||||
const path nested_dir_name = "dir2";
|
||||
const path nested_dir = env.create_dir("dir/dir2");
|
||||
|
||||
for (auto& FI : files) {
|
||||
env.create_file(dir / FI.filename, FI.size);
|
||||
env.create_file(nested_dir / FI.filename, FI.size);
|
||||
}
|
||||
{ // test for non-existant directory
|
||||
const path dest = env.make_env_path("dest_dir1");
|
||||
std::error_code ec;
|
||||
fs::copy(dir, dest, ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_CHECK(is_directory(dest));
|
||||
for (auto& FI : files) {
|
||||
path created = dest / FI.filename;
|
||||
TEST_CHECK(is_regular_file(created));
|
||||
TEST_CHECK(file_size(created) == FI.size);
|
||||
}
|
||||
TEST_CHECK(!is_directory(dest / nested_dir_name));
|
||||
}
|
||||
{ // test for existing directory
|
||||
const path dest = env.create_dir("dest_dir2");
|
||||
std::error_code ec;
|
||||
fs::copy(dir, dest, ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_CHECK(is_directory(dest));
|
||||
for (auto& FI : files) {
|
||||
path created = dest / FI.filename;
|
||||
TEST_CHECK(is_regular_file(created));
|
||||
TEST_CHECK(file_size(created) == FI.size);
|
||||
}
|
||||
TEST_CHECK(!is_directory(dest / nested_dir_name));
|
||||
}
|
||||
{ // test recursive copy
|
||||
const path dest = env.make_env_path("dest_dir3");
|
||||
std::error_code ec;
|
||||
fs::copy(dir, dest, CO::recursive, ec);
|
||||
TEST_REQUIRE(!ec);
|
||||
TEST_CHECK(is_directory(dest));
|
||||
const path nested_dest = dest / nested_dir_name;
|
||||
TEST_REQUIRE(is_directory(nested_dest));
|
||||
for (auto& FI : files) {
|
||||
path created = dest / FI.filename;
|
||||
path nested_created = nested_dest / FI.filename;
|
||||
TEST_CHECK(is_regular_file(created));
|
||||
TEST_CHECK(file_size(created) == FI.size);
|
||||
TEST_CHECK(is_regular_file(nested_created));
|
||||
TEST_CHECK(file_size(nested_created) == FI.size);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
TEST_SUITE_END()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user