| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() | ||
| { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| dne |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| dir3 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| dir1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| empty_file |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
| } | ||
| } |