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:
Eric Fiselier 2016-06-17 19:46:40 +00:00
parent 7a5813597d
commit c79795874a
147 changed files with 15301 additions and 11 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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}")

View 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

View 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

View 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

View File

@ -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)

View File

@ -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();
}

View File

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

View File

@ -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()
{
}

View File

@ -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:

View File

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

View File

@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

View File

@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

View File

@ -0,0 +1,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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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.
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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() {}

View File

@ -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");
}

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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);
}
}

View File

@ -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>();
}

View File

@ -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>();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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()
{
}

View File

@ -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, "");
}

View File

@ -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()

View File

@ -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()

View File

@ -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