diff options
author | Eric Fiselier <eric@efcs.ca> | 2018-07-27 03:07:09 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2018-07-27 03:07:09 +0000 |
commit | 998a5c88312066fcc2b2de1358edc76587611354 (patch) | |
tree | f3e74cc7ce9e55f30e7019dd6e379571c91aaa1f /libcxx/test/std/input.output/filesystems/class.directory_entry | |
parent | 567485a72ff71e34c9e25aaab8eecfda3aa6cd62 (diff) | |
download | bcm5719-llvm-998a5c88312066fcc2b2de1358edc76587611354.tar.gz bcm5719-llvm-998a5c88312066fcc2b2de1358edc76587611354.zip |
Implement <filesystem>
This patch implements the <filesystem> header and uses that
to provide <experimental/filesystem>.
Unlike other standard headers, the symbols needed for <filesystem>
have not yet been placed in libc++.so. Instead they live in the
new libc++fs.a library. Users of filesystem are required to link this
library. (Also note that libc++experimental no longer contains the
definition of <experimental/filesystem>, which now requires linking libc++fs).
The reason for keeping <filesystem> out of the dylib for now is that
it's still somewhat experimental, and the possibility of requiring an
ABI breaking change is very real. In the future the symbols will likely
be moved into the dylib, or the dylib will be made to link libc++fs automagically).
Note that moving the symbols out of libc++experimental may break user builds
until they update to -lc++fs. This should be OK, because the experimental
library provides no stability guarantees. However, I plan on looking into
ways we can force libc++experimental to automagically link libc++fs.
In order to use a single implementation and set of tests for <filesystem>, it
has been placed in a special `__fs` namespace. This namespace is inline in
C++17 onward, but not before that. As such implementation is available
in C++11 onward, but no filesystem namespace is present "directly", and
as such name conflicts shouldn't occur in C++11 or C++14.
llvm-svn: 338093
Diffstat (limited to 'libcxx/test/std/input.output/filesystems/class.directory_entry')
18 files changed, 2435 insertions, 0 deletions
diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/copy.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/copy.pass.cpp new file mode 100644 index 00000000000..a81d5ea7960 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/copy.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// directory_entry(const directory_entry&) = default; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" +#include "test_convertible.hpp" + +TEST_SUITE(directory_entry_path_ctor_suite) + +TEST_CASE(copy_ctor) { + using namespace fs; + // Copy + { + static_assert(std::is_copy_constructible<directory_entry>::value, + "directory_entry must be copy constructible"); + static_assert(!std::is_nothrow_copy_constructible<directory_entry>::value, + "directory_entry's copy constructor cannot be noexcept"); + const path p("foo/bar/baz"); + const directory_entry e(p); + assert(e.path() == p); + directory_entry e2(e); + assert(e.path() == p); + assert(e2.path() == p); + } +} + +TEST_CASE(copy_ctor_copies_cache) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym = env.create_symlink("dir/file", "sym"); + + { + directory_entry ent(sym); + + fs::remove(sym); + + directory_entry ent_cp(ent); + TEST_CHECK(ent_cp.path() == sym); + TEST_CHECK(ent_cp.is_symlink()); + } + + { + directory_entry ent(file); + + fs::remove(file); + + directory_entry ent_cp(ent); + TEST_CHECK(ent_cp.path() == file); + TEST_CHECK(ent_cp.is_regular_file()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/copy_assign.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/copy_assign.pass.cpp new file mode 100644 index 00000000000..204207276cb --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/copy_assign.pass.cpp @@ -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 + +// <filesystem> + +// class directory_entry + +// directory_entry& operator=(directory_entry const&) = default; +// directory_entry& operator=(directory_entry&&) noexcept = default; +// void assign(path const&); +// void replace_filename(path const&); + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" + +TEST_SUITE(directory_entry_ctor_suite) + +TEST_CASE(test_copy_assign_operator) { + using namespace fs; + // Copy + { + static_assert(std::is_copy_assignable<directory_entry>::value, + "directory_entry must be copy assignable"); + static_assert(!std::is_nothrow_copy_assignable<directory_entry>::value, + "directory_entry's copy assignment cannot be noexcept"); + const path p("foo/bar/baz"); + const path p2("abc"); + const directory_entry e(p); + directory_entry e2; + assert(e.path() == p && e2.path() == path()); + e2 = e; + assert(e.path() == p && e2.path() == p); + directory_entry e3(p2); + e2 = e3; + assert(e2.path() == p2 && e3.path() == p2); + } +} + +TEST_CASE(copy_assign_copies_cache) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym = env.create_symlink("dir/file", "sym"); + + { + directory_entry ent(sym); + + fs::remove(sym); + + directory_entry ent_cp; + ent_cp = ent; + TEST_CHECK(ent_cp.path() == sym); + TEST_CHECK(ent_cp.is_symlink()); + } + + { + directory_entry ent(file); + + fs::remove(file); + + directory_entry ent_cp; + ent_cp = ent; + TEST_CHECK(ent_cp.path() == file); + TEST_CHECK(ent_cp.is_regular_file()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/default.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/default.pass.cpp new file mode 100644 index 00000000000..1d83cc69d6c --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/default.pass.cpp @@ -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 + +// <filesystem> + +// class directory_entry + +// directory_entry() noexcept = default; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +int main() { + 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()); + } +} diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/default_const.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/default_const.pass.cpp new file mode 100644 index 00000000000..240541d203d --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/default_const.pass.cpp @@ -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 +// XFAIL: apple-clang-7, clang-3.7, clang-3.8 + +// <filesystem> + +// class directory_entry + +// directory_entry() noexcept = default; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +int main() { + using namespace fs; + // Default + { + static_assert(std::is_nothrow_default_constructible<directory_entry>::value, + "directory_entry must have a nothrow default constructor"); + const directory_entry e; + assert(e.path() == path()); + } +} diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/move.pass.cpp new file mode 100644 index 00000000000..238a8549ea3 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/move.pass.cpp @@ -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 + +// <filesystem> + +// class directory_entry + +// directory_entry(directory_entry&&) noexcept = default; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" +#include "test_convertible.hpp" + +TEST_SUITE(directory_entry_path_ctor_suite) + +TEST_CASE(move_ctor) { + using namespace fs; + // Move + { + static_assert(std::is_nothrow_move_constructible<directory_entry>::value, + "directory_entry must be nothrow move constructible"); + const path p("foo/bar/baz"); + directory_entry e(p); + assert(e.path() == p); + directory_entry e2(std::move(e)); + assert(e2.path() == p); + assert(e.path() != p); // Testing moved from state. + } +} + +TEST_CASE(move_ctor_copies_cache) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym = env.create_symlink("dir/file", "sym"); + + { + directory_entry ent(sym); + + fs::remove(sym); + + directory_entry ent_cp(std::move(ent)); + TEST_CHECK(ent_cp.path() == sym); + TEST_CHECK(ent_cp.is_symlink()); + } + + { + directory_entry ent(file); + + fs::remove(file); + + directory_entry ent_cp(std::move(ent)); + TEST_CHECK(ent_cp.path() == file); + TEST_CHECK(ent_cp.is_regular_file()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/move_assign.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/move_assign.pass.cpp new file mode 100644 index 00000000000..f104980c9c4 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/move_assign.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// directory_entry& operator=(directory_entry const&) = default; +// directory_entry& operator=(directory_entry&&) noexcept = default; +// void assign(path const&); +// void replace_filename(path const&); + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" + +TEST_SUITE(directory_entry_ctor_suite) + +TEST_CASE(test_move_assign_operator) { + using namespace fs; + // Copy + { + static_assert(std::is_nothrow_move_assignable<directory_entry>::value, + "directory_entry is noexcept move assignable"); + const path p("foo/bar/baz"); + const path p2("abc"); + directory_entry e(p); + directory_entry e2(p2); + assert(e.path() == p && e2.path() == p2); + e2 = std::move(e); + assert(e2.path() == p); + assert(e.path() != p); // testing moved from state + } +} + +TEST_CASE(move_assign_copies_cache) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym = env.create_symlink("dir/file", "sym"); + + { + directory_entry ent(sym); + + fs::remove(sym); + + directory_entry ent_cp; + ent_cp = std::move(ent); + TEST_CHECK(ent_cp.path() == sym); + TEST_CHECK(ent_cp.is_symlink()); + } + + { + directory_entry ent(file); + + fs::remove(file); + + directory_entry ent_cp; + ent_cp = std::move(ent); + TEST_CHECK(ent_cp.path() == file); + TEST_CHECK(ent_cp.is_regular_file()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp new file mode 100644 index 00000000000..b06bd129384 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp @@ -0,0 +1,182 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// explicit directory_entry(const path); +// directory_entry(const path&, error_code& ec); + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" +#include "test_convertible.hpp" + +TEST_SUITE(directory_entry_path_ctor_suite) + +TEST_CASE(path_ctor) { + using namespace fs; + { + static_assert(std::is_constructible<directory_entry, const path&>::value, + "directory_entry must be constructible from path"); + static_assert( + !std::is_nothrow_constructible<directory_entry, const path&>::value, + "directory_entry constructor should not be noexcept"); + static_assert(!std::is_convertible<path const&, directory_entry>::value, + "directory_entry constructor should be explicit"); + } + { + const path p("foo/bar/baz"); + const directory_entry e(p); + TEST_CHECK(e.path() == p); + } +} + +TEST_CASE(path_ec_ctor) { + using namespace fs; + { + static_assert( + std::is_constructible<directory_entry, const path&, + std::error_code&>::value, + "directory_entry must be constructible from path and error_code"); + static_assert(!std::is_nothrow_constructible<directory_entry, const path&, + std::error_code&>::value, + "directory_entry constructor should not be noexcept"); + static_assert( + test_convertible<directory_entry, const path&, std::error_code&>(), + "directory_entry constructor should not be explicit"); + } + { + std::error_code ec = GetTestEC(); + const directory_entry e(StaticEnv::File, ec); + TEST_CHECK(e.path() == StaticEnv::File); + TEST_CHECK(!ec); + } + { + const path p("foo/bar/baz"); + std::error_code ec = GetTestEC(); + const directory_entry e(p, ec); + TEST_CHECK(e.path() == p); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + } +} + +TEST_CASE(path_ctor_calls_refresh) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym = env.create_symlink("dir/file", "sym"); + + { + directory_entry ent(file); + std::error_code ec = GetTestEC(); + directory_entry ent_ec(file, ec); + TEST_CHECK(!ec); + + LIBCPP_ONLY(remove(file)); + + TEST_CHECK(ent.exists()); + TEST_CHECK(ent_ec.exists()); + + TEST_CHECK(ent.file_size() == 42); + TEST_CHECK(ent_ec.file_size() == 42); + } + + env.create_file("dir/file", 101); + + { + directory_entry ent(sym); + std::error_code ec = GetTestEC(); + directory_entry ent_ec(sym, ec); + TEST_CHECK(!ec); + + LIBCPP_ONLY(remove(file)); + LIBCPP_ONLY(remove(sym)); + + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent_ec.is_symlink()); + + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent_ec.is_regular_file()); + + TEST_CHECK(ent.file_size() == 101); + TEST_CHECK(ent_ec.file_size() == 101); + } +} + +TEST_CASE(path_ctor_dne) { + using namespace fs; + + { + std::error_code ec = GetTestEC(); + directory_entry ent(StaticEnv::DNE, ec); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + TEST_CHECK(ent.path() == StaticEnv::DNE); + } + // don't report dead symlinks as an error. + { + std::error_code ec = GetTestEC(); + directory_entry ent(StaticEnv::BadSymlink, ec); + TEST_CHECK(!ec); + TEST_CHECK(ent.path() == StaticEnv::BadSymlink); + } + // DNE does not cause the constructor to throw + { + directory_entry ent(StaticEnv::DNE); + TEST_CHECK(ent.path() == StaticEnv::DNE); + + directory_entry ent_two(StaticEnv::BadSymlink); + TEST_CHECK(ent_two.path() == StaticEnv::BadSymlink); + } +} + +TEST_CASE(path_ctor_cannot_resolve) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_out_of_dir = env.create_file("file1", 101); + const path sym_out_of_dir = env.create_symlink("dir/file", "sym"); + const path sym_in_dir = env.create_symlink("dir/file1", "dir/sym2"); + permissions(dir, perms::none); + + { + std::error_code ec = GetTestEC(); + directory_entry ent(file, ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + TEST_CHECK(ent.path() == file); + } + { + std::error_code ec = GetTestEC(); + directory_entry ent(sym_in_dir, ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + TEST_CHECK(ent.path() == sym_in_dir); + } + { + std::error_code ec = GetTestEC(); + directory_entry ent(sym_out_of_dir, ec); + TEST_CHECK(!ec); + TEST_CHECK(ent.path() == sym_out_of_dir); + } + { + TEST_CHECK_NO_THROW(directory_entry(file)); + TEST_CHECK_NO_THROW(directory_entry(sym_in_dir)); + TEST_CHECK_NO_THROW(directory_entry(sym_out_of_dir)); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/assign.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/assign.pass.cpp new file mode 100644 index 00000000000..d19c8c2ad87 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/assign.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// directory_entry& operator=(directory_entry const&) = default; +// directory_entry& operator=(directory_entry&&) noexcept = default; +// void assign(path const&); +// void replace_filename(path const&); + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" + +TEST_SUITE(directory_entry_mods_suite) + +TEST_CASE(test_path_assign_method) { + using namespace fs; + const path p("foo/bar/baz"); + const path p2("abc"); + directory_entry e(p); + { + static_assert(std::is_same<decltype(e.assign(p)), void>::value, + "return type should be void"); + static_assert(noexcept(e.assign(p)) == false, + "operation must not be noexcept"); + } + { + TEST_CHECK(e.path() == p); + e.assign(p2); + TEST_CHECK(e.path() == p2 && e.path() != p); + e.assign(p); + TEST_CHECK(e.path() == p && e.path() != p2); + } +} + +TEST_CASE(test_path_assign_ec_method) { + using namespace fs; + const path p("foo/bar/baz"); + const path p2("abc"); + { + std::error_code ec; + directory_entry e(p); + static_assert(std::is_same<decltype(e.assign(p, ec)), void>::value, + "return type should be void"); + static_assert(noexcept(e.assign(p, ec)) == false, + "operation must not be noexcept"); + } + { + directory_entry ent(p); + std::error_code ec = GetTestEC(); + ent.assign(p2, ec); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + TEST_CHECK(ent.path() == p2); + } +} + +TEST_CASE(test_assign_calls_refresh) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym = env.create_symlink("dir/file", "sym"); + + { + directory_entry ent; + ent.assign(file); + + // removing the file demonstrates that the values where cached previously. + LIBCPP_ONLY(remove(file)); + + TEST_CHECK(ent.is_regular_file()); + } + env.create_file("dir/file", 101); + { + directory_entry ent; + ent.assign(sym); + + LIBCPP_ONLY(remove(file)); + LIBCPP_ONLY(remove(sym)); + + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + } +} + +TEST_CASE(test_assign_propagates_error) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym_out_of_dir = env.create_symlink("dir/file", "sym"); + const path file_out_of_dir = env.create_file("file1"); + const path sym_in_dir = env.create_symlink("file1", "dir/sym1"); + + permissions(dir, perms::none); + + { + directory_entry ent; + std::error_code ec = GetTestEC(); + ent.assign(file, ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + } + { + directory_entry ent; + std::error_code ec = GetTestEC(); + ent.assign(sym_in_dir, ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + } + { + directory_entry ent; + std::error_code ec = GetTestEC(); + ent.assign(sym_out_of_dir, ec); + TEST_CHECK(!ec); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/refresh.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/refresh.pass.cpp new file mode 100644 index 00000000000..575f0d59b4c --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/refresh.pass.cpp @@ -0,0 +1,341 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// directory_entry& operator=(directory_entry const&) = default; +// directory_entry& operator=(directory_entry&&) noexcept = default; +// void assign(path const&); +// void replace_filename(path const&); + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" + +TEST_SUITE(directory_entry_mods_suite) + +TEST_CASE(test_refresh_method) { + using namespace fs; + { + directory_entry e; + static_assert(noexcept(e.refresh()) == false, + "operation cannot be noexcept"); + static_assert(std::is_same<decltype(e.refresh()), void>::value, + "operation must return void"); + } + { + directory_entry e; + e.refresh(); + TEST_CHECK(!e.exists()); + } +} + +TEST_CASE(test_refresh_ec_method) { + using namespace fs; + { + directory_entry e; + std::error_code ec; + static_assert(noexcept(e.refresh(ec)), "operation should be noexcept"); + static_assert(std::is_same<decltype(e.refresh(ec)), void>::value, + "operation must return void"); + } + { + directory_entry e; + std::error_code ec = GetTestEC(); + e.refresh(ec); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + } +} + +TEST_CASE(refresh_on_file_dne) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + + const perms old_perms = status(dir).permissions(); + + // test file doesn't exist + { + directory_entry ent(file); + remove(file); + TEST_CHECK(ent.exists()); + + ent.refresh(); + + permissions(dir, perms::none); + TEST_CHECK(!ent.exists()); + } + permissions(dir, old_perms); + env.create_file("dir/file", 101); + { + directory_entry ent(file); + remove(file); + TEST_CHECK(ent.exists()); + + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + permissions(dir, perms::none); + TEST_CHECK(!ent.exists()); + } +} + +void remove_if_exists(const fs::path& p) { + std::error_code ec; + remove(p, ec); +} + +TEST_CASE(refresh_on_bad_symlink) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path sym = env.create_symlink("dir/file", "sym"); + + const perms old_perms = status(dir).permissions(); + + // test file doesn't exist + { + directory_entry ent(sym); + LIBCPP_ONLY(remove(file)); + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent.exists()); + + remove_if_exists(file); + ent.refresh(); + + LIBCPP_ONLY(permissions(dir, perms::none)); + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(!ent.is_regular_file()); + TEST_CHECK(!ent.exists()); + } + permissions(dir, old_perms); + env.create_file("dir/file", 101); + { + directory_entry ent(sym); + LIBCPP_ONLY(remove(file)); + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent.exists()); + + remove_if_exists(file); + + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(!ec); // we don't report bad symlinks as an error. + + LIBCPP_ONLY(permissions(dir, perms::none)); + TEST_CHECK(!ent.exists()); + } +} + +TEST_CASE(refresh_cannot_resolve) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_out_of_dir = env.create_file("file1", 99); + const path sym_out_of_dir = env.create_symlink("dir/file", "sym"); + const path sym_in_dir = env.create_symlink("file1", "dir/sym1"); + perms old_perms = status(dir).permissions(); + + { + directory_entry ent(file); + permissions(dir, perms::none); + + TEST_CHECK(ent.is_regular_file()); + + std::error_code ec = GetTestEC(); + ent.refresh(ec); + + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + TEST_CHECK(ent.path() == file); + + ExceptionChecker Checker(file, std::errc::permission_denied, + "directory_entry::refresh"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh()); + } + permissions(dir, old_perms); + { + directory_entry ent(sym_in_dir); + permissions(dir, perms::none); + TEST_CHECK(ent.is_symlink()); + + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + TEST_CHECK(ent.path() == sym_in_dir); + + ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied, + "directory_entry::refresh"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.refresh()); + } + permissions(dir, old_perms); + { + directory_entry ent(sym_out_of_dir); + permissions(dir, perms::none); + TEST_CHECK(ent.is_symlink()); + + // Failure to resolve the linked entity due to permissions is not + // reported as an error. + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(!ec); + TEST_CHECK(ent.is_symlink()); + + ec = GetTestEC(); + TEST_CHECK(ent.exists(ec) == false); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + TEST_CHECK(ent.path() == sym_out_of_dir); + } + permissions(dir, old_perms); + { + directory_entry ent_file(file); + directory_entry ent_sym(sym_in_dir); + directory_entry ent_sym2(sym_out_of_dir); + permissions(dir, perms::none); + ((void)ent_file); + ((void)ent_sym); + + TEST_CHECK_THROW(filesystem_error, ent_file.refresh()); + TEST_CHECK_THROW(filesystem_error, ent_sym.refresh()); + TEST_CHECK_NO_THROW(ent_sym2); + } +} + +TEST_CASE(refresh_doesnt_throw_on_dne_but_reports_it) { + using namespace fs; + scoped_test_env env; + + const path file = env.create_file("file1", 42); + const path sym = env.create_symlink("file1", "sym"); + + { + directory_entry ent(file); + TEST_CHECK(ent.file_size() == 42); + + remove(file); + + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + TEST_CHECK_NO_THROW(ent.refresh()); + + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + // doesn't throw! + TEST_CHECK_THROW(filesystem_error, ent.file_size()); + } + env.create_file("file1", 99); + { + directory_entry ent(sym); + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent.file_size() == 99); + + remove(file); + + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(!ec); + + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + TEST_CHECK_THROW(filesystem_error, ent.file_size()); + } +} + +TEST_CASE(access_cache_after_refresh_fails) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_out_of_dir = env.create_file("file1", 101); + const path sym = env.create_symlink("dir/file", "sym"); + const path sym_in_dir = env.create_symlink("dir/file", "dir/sym2"); + + const perms old_perms = status(dir).permissions(); + +#define CHECK_ACCESS(func, expect) \ + ec = GetTestEC(); \ + TEST_CHECK(ent.func(ec) == expect); \ + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)) + + // test file doesn't exist + { + directory_entry ent(file); + + TEST_CHECK(!ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent.exists()); + + permissions(dir, perms::none); + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + CHECK_ACCESS(exists, false); + CHECK_ACCESS(is_symlink, false); + CHECK_ACCESS(last_write_time, file_time_type::min()); + CHECK_ACCESS(hard_link_count, uintmax_t(-1)); + } + permissions(dir, old_perms); + { + directory_entry ent(sym_in_dir); + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent.exists()); + + permissions(dir, perms::none); + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + CHECK_ACCESS(exists, false); + CHECK_ACCESS(is_symlink, false); + CHECK_ACCESS(last_write_time, file_time_type::min()); + CHECK_ACCESS(hard_link_count, uintmax_t(-1)); + } + permissions(dir, old_perms); + { + directory_entry ent(sym); + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent.exists()); + + permissions(dir, perms::none); + std::error_code ec = GetTestEC(); + ent.refresh(ec); + TEST_CHECK(!ec); + TEST_CHECK(ent.is_symlink()); + + CHECK_ACCESS(exists, false); + CHECK_ACCESS(is_regular_file, false); + CHECK_ACCESS(last_write_time, file_time_type::min()); + CHECK_ACCESS(hard_link_count, uintmax_t(-1)); + } +#undef CHECK_ACCESS +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/replace_filename.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/replace_filename.pass.cpp new file mode 100644 index 00000000000..4a9b76d6375 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/replace_filename.pass.cpp @@ -0,0 +1,169 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// directory_entry& operator=(directory_entry const&) = default; +// directory_entry& operator=(directory_entry&&) noexcept = default; +// void assign(path const&); +// void replace_filename(path const&); + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "rapid-cxx-test.hpp" +#include "filesystem_test_helper.hpp" + +TEST_SUITE(directory_entry_mods_suite) + +TEST_CASE(test_replace_filename_method) { + using namespace fs; + + { + directory_entry e; + path replace; + static_assert(noexcept(e.replace_filename(replace)) == false, + "operation cannot be noexcept"); + static_assert( + std::is_same<decltype(e.replace_filename(replace)), void>::value, + "operation must return void"); + } + { + const path p("/path/to/foo.exe"); + const path replace("bar.out"); + const path expect("/path/to/bar.out"); + directory_entry e(p); + TEST_CHECK(e.path() == p); + e.replace_filename(replace); + TEST_CHECK(e.path() == expect); + } +} + +TEST_CASE(test_replace_filename_ec_method) { + using namespace fs; + + { + directory_entry e; + path replace; + std::error_code ec; + static_assert(noexcept(e.replace_filename(replace, ec)) == false, + "operation cannot be noexcept"); + static_assert( + std::is_same<decltype(e.replace_filename(replace, ec)), void>::value, + "operation must return void"); + } + { + const path p("/path/to/foo.exe"); + const path replace("bar.out"); + const path expect("/path/to/bar.out"); + directory_entry e(p); + TEST_CHECK(e.path() == p); + std::error_code ec = GetTestEC(); + e.replace_filename(replace, ec); + TEST_CHECK(e.path() == expect); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + } + { + const path p = StaticEnv::EmptyFile; + const path expect = StaticEnv::NonEmptyFile; + const path replace = StaticEnv::NonEmptyFile.filename(); + TEST_REQUIRE(expect.parent_path() == p.parent_path()); + directory_entry e(p); + TEST_CHECK(e.path() == p); + std::error_code ec = GetTestEC(); + e.replace_filename(replace, ec); + TEST_CHECK(e.path() == expect); + TEST_CHECK(!ec); + } +} + +TEST_CASE(test_replace_filename_calls_refresh) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_two = env.create_file("dir/file_two", 101); + const path sym = env.create_symlink("dir/file", "sym"); + const path sym_two = env.create_symlink("dir/file_two", "sym_two"); + + { + directory_entry ent(file); + ent.replace_filename(file_two.filename()); + TEST_REQUIRE(ent.path() == file_two); + + // removing the file demonstrates that the values where cached previously. + LIBCPP_ONLY(remove(file_two)); + + TEST_CHECK(ent.file_size() == 101); + } + env.create_file("dir/file_two", 99); + { + directory_entry ent(sym); + ent.replace_filename(sym_two.filename()); + TEST_REQUIRE(ent.path() == sym_two); + + LIBCPP_ONLY(remove(file_two)); + LIBCPP_ONLY(remove(sym_two)); + + TEST_CHECK(ent.is_symlink()); + TEST_CHECK(ent.is_regular_file()); + TEST_CHECK(ent.file_size() == 99); + } +} + +TEST_CASE(test_replace_filename_propagates_error) { + using namespace fs; + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_two = env.create_file("dir/file_two", 99); + const path file_out_of_dir = env.create_file("file_three", 101); + const path sym_out_of_dir = env.create_symlink("dir/file", "sym"); + const path sym_out_of_dir_two = env.create_symlink("dir/file", "sym_two"); + const path sym_in_dir = env.create_symlink("file_two", "dir/sym_three"); + const path sym_in_dir_two = env.create_symlink("file_two", "dir/sym_four"); + + const perms old_perms = status(dir).permissions(); + + { + directory_entry ent(file); + permissions(dir, perms::none); + std::error_code ec = GetTestEC(); + ent.replace_filename(file_two.filename(), ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + } + permissions(dir, old_perms); + { + directory_entry ent(sym_in_dir); + permissions(dir, perms::none); + std::error_code ec = GetTestEC(); + ent.replace_filename(sym_in_dir_two.filename(), ec); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + } + permissions(dir, old_perms); + { + directory_entry ent(sym_out_of_dir); + permissions(dir, perms::none); + std::error_code ec = GetTestEC(); + ent.replace_filename(sym_out_of_dir_two.filename(), ec); + TEST_CHECK(!ec); + TEST_CHECK(ent.is_symlink()); + ec = GetTestEC(); + TEST_CHECK(!ent.exists(ec)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/comparisons.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/comparisons.pass.cpp new file mode 100644 index 00000000000..7df36fed3a6 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/comparisons.pass.cpp @@ -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 + +// <filesystem> + +// class directory_entry + +// bool operator==(directory_entry const&) const noexcept; +// bool operator!=(directory_entry const&) const noexcept; +// bool operator< (directory_entry const&) const noexcept; +// bool operator<=(directory_entry const&) const noexcept; +// bool operator> (directory_entry const&) const noexcept; +// bool operator>=(directory_entry const&) const noexcept; + + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + + +#define CHECK_OP(Op) \ + static_assert(std::is_same<decltype(ce. operator Op (ce)), bool>::value, ""); \ + static_assert(noexcept(ce.operator Op (ce)), "Operation must be noexcept" ) + +void test_comparison_signatures() { + using namespace fs; + path const p("foo/bar/baz"); + // Check that the operators are member functions with the correct signatures. + { + directory_entry const ce(p); + CHECK_OP(==); + CHECK_OP(!=); + CHECK_OP(< ); + CHECK_OP(<=); + CHECK_OP(> ); + CHECK_OP(>=); + } +} +#undef CHECK_OP + +// The actual semantics of the comparisons are testing via paths operators. +void test_comparisons_simple() { + using namespace fs; + typedef std::pair<path, path> TestType; + TestType TestCases[] = + { + {"", ""}, + {"", "a"}, + {"a", "a"}, + {"a", "b"}, + {"foo/bar/baz", "foo/bar/baz/"} + }; + auto TestFn = [](path const& LHS, const directory_entry& LHSE, + path const& RHS, const directory_entry& RHSE) { + assert((LHS == RHS) == (LHSE == RHSE)); + assert((LHS != RHS) == (LHSE != RHSE)); + assert((LHS < RHS) == (LHSE < RHSE)); + assert((LHS <= RHS) == (LHSE <= RHSE)); + assert((LHS > RHS) == (LHSE > RHSE)); + assert((LHS >= RHS) == (LHSE >= RHSE)); + }; + for (auto const& TC : TestCases) { + const directory_entry L(TC.first); + const directory_entry R(TC.second); + TestFn(TC.first, L, TC.second, R); + TestFn(TC.second, R, TC.first, L); + } +} + +int main() { + test_comparison_signatures(); + test_comparisons_simple(); +} diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/file_size.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/file_size.pass.cpp new file mode 100644 index 00000000000..04dec92c9c9 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/file_size.pass.cpp @@ -0,0 +1,242 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// uintmax_t file_size() const; +// uintmax_t file_size(error_code const&) const noexcept; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "filesystem_test_helper.hpp" +#include "rapid-cxx-test.hpp" + +#include <iostream> + +TEST_SUITE(directory_entry_obs_testsuite) + +TEST_CASE(signatures) { + using namespace fs; + { + const fs::directory_entry e = {}; + std::error_code ec; + static_assert(std::is_same<decltype(e.file_size()), uintmax_t>::value, ""); + static_assert(std::is_same<decltype(e.file_size(ec)), uintmax_t>::value, + ""); + static_assert(noexcept(e.file_size()) == false, ""); + static_assert(noexcept(e.file_size(ec)) == true, ""); + } +} + +TEST_CASE(basic) { + using namespace fs; + + scoped_test_env env; + const path file = env.create_file("file", 42); + const path dir = env.create_dir("dir"); + const path sym = env.create_symlink("file", "sym"); + + { + directory_entry ent(file); + uintmax_t expect = file_size(ent); + TEST_CHECK(expect == 42); + + // Remove the file to show that the results were already in the cache. + LIBCPP_ONLY(remove(file)); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == expect); + TEST_CHECK(!ec); + } + env.create_file("file", 99); + { + directory_entry ent(sym); + + uintmax_t expect = file_size(ent); + TEST_CHECK(expect == 99); + + LIBCPP_ONLY(remove(ent)); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == 99); + TEST_CHECK(!ec); + } +} + +TEST_CASE(not_regular_file) { + using namespace fs; + + scoped_test_env env; + struct { + const path p; + std::errc expected_err; + } TestCases[] = { + {env.create_dir("dir"), std::errc::is_a_directory}, + {env.create_fifo("fifo"), std::errc::not_supported}, + {env.create_symlink("dir", "sym"), std::errc::is_a_directory}}; + + for (auto const& TC : TestCases) { + const path& p = TC.p; + directory_entry ent(p); + TEST_CHECK(ent.path() == p); + std::error_code ec = GetTestEC(0); + + std::error_code other_ec = GetTestEC(1); + uintmax_t expect = file_size(p, other_ec); + + uintmax_t got = ent.file_size(ec); + TEST_CHECK(got == expect); + TEST_CHECK(got == uintmax_t(-1)); + TEST_CHECK(ec == other_ec); + TEST_CHECK(ErrorIs(ec, TC.expected_err)); + + ExceptionChecker Checker(p, TC.expected_err, "directory_entry::file_size"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size()); + } +} + +TEST_CASE(error_reporting) { + using namespace fs; + + scoped_test_env env; + + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_out_of_dir = env.create_file("file2", 101); + const path sym_out_of_dir = env.create_symlink("dir/file", "sym"); + const path sym_in_dir = env.create_symlink("file2", "dir/sym2"); + + const perms old_perms = status(dir).permissions(); + + // test a file which doesn't exist + { + directory_entry ent; + + std::error_code ec = GetTestEC(); + ent.assign(StaticEnv::DNE, ec); + TEST_REQUIRE(ent.path() == StaticEnv::DNE); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ExceptionChecker Checker(StaticEnv::DNE, + std::errc::no_such_file_or_directory, + "directory_entry::file_size"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size()); + } + // test a dead symlink + { + directory_entry ent; + + std::error_code ec = GetTestEC(); + uintmax_t expect_bad = file_size(StaticEnv::BadSymlink, ec); + TEST_CHECK(expect_bad == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ec = GetTestEC(); + ent.assign(StaticEnv::BadSymlink, ec); + TEST_REQUIRE(ent.path() == StaticEnv::BadSymlink); + TEST_CHECK(!ec); + + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == expect_bad); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ExceptionChecker Checker(StaticEnv::BadSymlink, + std::errc::no_such_file_or_directory, + "directory_entry::file_size"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size()); + } + // test a file w/o appropriate permissions. + { + directory_entry ent; + uintmax_t expect_good = file_size(file); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(file, ec); + TEST_REQUIRE(ent.path() == file); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(file, std::errc::permission_denied, "file_size"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.file_size()); + } + permissions(dir, old_perms); + // test a symlink w/o appropriate permissions. + { + directory_entry ent; + uintmax_t expect_good = file_size(sym_in_dir); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(sym_in_dir, ec); + TEST_REQUIRE(ent.path() == sym_in_dir); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied, + "file_size"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.file_size()); + } + permissions(dir, old_perms); + // test a symlink to a file w/o appropriate permissions + { + directory_entry ent; + uintmax_t expect_good = file_size(sym_out_of_dir); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(sym_out_of_dir, ec); + TEST_REQUIRE(ent.path() == sym_out_of_dir); + TEST_CHECK(!ec); + + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(sym_out_of_dir, std::errc::permission_denied, + "file_size"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.file_size()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.file_size(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.file_size()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/file_type_obs.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/file_type_obs.pass.cpp new file mode 100644 index 00000000000..2a0d80ca626 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/file_type_obs.pass.cpp @@ -0,0 +1,258 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// file_status status() const; +// file_status status(error_code const&) const noexcept; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "filesystem_test_helper.hpp" +#include "rapid-cxx-test.hpp" + +TEST_SUITE(directory_entry_obs_testsuite) + +TEST_CASE(file_dne) { + using namespace fs; + directory_entry p("dne"); +} + +TEST_CASE(signatures) { + using namespace fs; + const directory_entry e = {}; + std::error_code ec; +#define TEST_FUNC(name) \ + static_assert(std::is_same<decltype(e.name()), bool>::value, \ + "wrong return type"); \ + static_assert(noexcept(e.name()) == false, "should not be noexcept"); \ + static_assert(std::is_same<decltype(e.name(ec)), bool>::value, \ + "wrong return type"); \ + static_assert(noexcept(e.name(ec)) == true, "should be noexcept") + + TEST_FUNC(exists); + TEST_FUNC(is_block_file); + TEST_FUNC(is_character_file); + TEST_FUNC(is_directory); + TEST_FUNC(is_fifo); + TEST_FUNC(is_other); + TEST_FUNC(is_regular_file); + TEST_FUNC(is_socket); + TEST_FUNC(is_symlink); + +#undef TEST_FUNC +} + +TEST_CASE(test_without_ec) { + using namespace fs; + using fs::directory_entry; + using fs::file_status; + using fs::path; + + scoped_test_env env; + path f = env.create_file("foo", 42); + path d = env.create_dir("dir"); + path fifo = env.create_fifo("fifo"); + path hl = env.create_hardlink("foo", "hl"); + for (auto p : {hl, f, d, fifo}) { + directory_entry e(p); + file_status st = status(p); + file_status sym_st = symlink_status(p); + fs::remove(p); + TEST_REQUIRE(e.exists()); + TEST_REQUIRE(!exists(p)); + TEST_CHECK(e.exists() == exists(st)); + TEST_CHECK(e.is_block_file() == is_block_file(st)); + TEST_CHECK(e.is_character_file() == is_character_file(st)); + TEST_CHECK(e.is_directory() == is_directory(st)); + TEST_CHECK(e.is_fifo() == is_fifo(st)); + TEST_CHECK(e.is_other() == is_other(st)); + TEST_CHECK(e.is_regular_file() == is_regular_file(st)); + TEST_CHECK(e.is_socket() == is_socket(st)); + TEST_CHECK(e.is_symlink() == is_symlink(sym_st)); + } +} + +TEST_CASE(test_with_ec) { + using namespace fs; + using fs::directory_entry; + using fs::file_status; + using fs::path; + + scoped_test_env env; + path f = env.create_file("foo", 42); + path d = env.create_dir("dir"); + path fifo = env.create_fifo("fifo"); + path hl = env.create_hardlink("foo", "hl"); + for (auto p : {hl, f, d, fifo}) { + directory_entry e(p); + std::error_code status_ec = GetTestEC(); + std::error_code sym_status_ec = GetTestEC(1); + file_status st = status(p, status_ec); + file_status sym_st = symlink_status(p, sym_status_ec); + fs::remove(p); + std::error_code ec = GetTestEC(2); + auto CheckEC = [&](std::error_code const& other_ec) { + bool res = ec == other_ec; + ec = GetTestEC(2); + return res; + }; + + TEST_REQUIRE(e.exists(ec)); + TEST_CHECK(CheckEC(status_ec)); + TEST_REQUIRE(!exists(p)); + + TEST_CHECK(e.exists(ec) == exists(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_block_file(ec) == is_block_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_character_file(ec) == is_character_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_directory(ec) == is_directory(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_fifo(ec) == is_fifo(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_other(ec) == is_other(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_regular_file(ec) == is_regular_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_socket(ec) == is_socket(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_symlink(ec) == is_symlink(sym_st)); + TEST_CHECK(CheckEC(sym_status_ec)); + } +} + +TEST_CASE(test_with_ec_dne) { + using namespace fs; + using fs::directory_entry; + using fs::file_status; + using fs::path; + + for (auto p : {StaticEnv::DNE, StaticEnv::BadSymlink}) { + + directory_entry e(p); + std::error_code status_ec = GetTestEC(); + std::error_code sym_status_ec = GetTestEC(1); + file_status st = status(p, status_ec); + file_status sym_st = symlink_status(p, sym_status_ec); + std::error_code ec = GetTestEC(2); + auto CheckEC = [&](std::error_code const& other_ec) { + bool res = ec == other_ec; + ec = GetTestEC(2); + return res; + }; + + TEST_CHECK(e.exists(ec) == exists(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_block_file(ec) == is_block_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_character_file(ec) == is_character_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_directory(ec) == is_directory(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_fifo(ec) == is_fifo(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_other(ec) == is_other(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_regular_file(ec) == is_regular_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_socket(ec) == is_socket(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_symlink(ec) == is_symlink(sym_st)); + TEST_CHECK(CheckEC(sym_status_ec)); + } +} + +TEST_CASE(test_with_ec_cannot_resolve) { + using namespace fs; + using fs::directory_entry; + using fs::file_status; + using fs::path; + + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_out_of_dir = env.create_file("file2", 99); + const path sym = env.create_symlink("file2", "dir/sym"); + + perms old_perms = fs::status(dir).permissions(); + + for (auto p : {file, sym}) { + permissions(dir, old_perms); + directory_entry e(p); + + permissions(dir, perms::none); + std::error_code dummy_ec; + e.refresh(dummy_ec); + TEST_REQUIRE(dummy_ec); + + std::error_code status_ec = GetTestEC(); + std::error_code sym_status_ec = GetTestEC(1); + file_status st = status(p, status_ec); + file_status sym_st = symlink_status(p, sym_status_ec); + std::error_code ec = GetTestEC(2); + auto CheckEC = [&](std::error_code const& other_ec) { + bool res = ec == other_ec; + ec = GetTestEC(2); + return res; + }; + + TEST_CHECK(e.exists(ec) == exists(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_block_file(ec) == is_block_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_character_file(ec) == is_character_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_directory(ec) == is_directory(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_fifo(ec) == is_fifo(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_other(ec) == is_other(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_regular_file(ec) == is_regular_file(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_socket(ec) == is_socket(st)); + TEST_CHECK(CheckEC(status_ec)); + + TEST_CHECK(e.is_symlink(ec) == is_symlink(sym_st)); + TEST_CHECK(CheckEC(sym_status_ec)); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/hard_link_count.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/hard_link_count.pass.cpp new file mode 100644 index 00000000000..17124c132cb --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/hard_link_count.pass.cpp @@ -0,0 +1,242 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// uintmax_t hard_link_count() const; +// uintmax_t hard_link_count(error_code const&) const noexcept; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "filesystem_test_helper.hpp" +#include "rapid-cxx-test.hpp" + +TEST_SUITE(directory_entry_obs_testsuite) + +TEST_CASE(signatures) { + using namespace fs; + { + const directory_entry e = {}; + std::error_code ec; + static_assert(std::is_same<decltype(e.hard_link_count()), uintmax_t>::value, ""); + static_assert(std::is_same<decltype(e.hard_link_count(ec)), uintmax_t>::value, + ""); + static_assert(noexcept(e.hard_link_count()) == false, ""); + static_assert(noexcept(e.hard_link_count(ec)) == true, ""); + } +} + +TEST_CASE(basic) { + using namespace fs; + + scoped_test_env env; + const path file = env.create_file("file", 42); + const path dir = env.create_dir("dir"); + const path sym = env.create_symlink("file", "sym"); + + { + directory_entry ent(file); + uintmax_t expect = hard_link_count(ent); + + // Remove the file to show that the results were already in the cache. + LIBCPP_ONLY(remove(file)); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == expect); + TEST_CHECK(!ec); + } + { + directory_entry ent(dir); + uintmax_t expect = hard_link_count(ent); + + LIBCPP_ONLY(remove(dir)); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == expect); + TEST_CHECK(!ec); + } + env.create_file("file", 99); + env.create_hardlink("file", "hl"); + { + directory_entry ent(sym); + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == 2); + TEST_CHECK(!ec); + } +} + +TEST_CASE(not_regular_file) { + using namespace fs; + + scoped_test_env env; + const path dir = env.create_dir("dir"); + const path dir2 = env.create_dir("dir/dir2"); + const path fifo = env.create_fifo("dir/fifo"); + const path sym_to_fifo = env.create_symlink("dir/fifo", "dir/sym"); + + const perms old_perms = status(dir).permissions(); + + for (auto p : {dir2, fifo, sym_to_fifo}) { + permissions(dir, old_perms); + std::error_code dummy_ec = GetTestEC(); + directory_entry ent(p, dummy_ec); + TEST_CHECK(!dummy_ec); + + uintmax_t expect = hard_link_count(p); + + LIBCPP_ONLY(permissions(dir, perms::none)); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == expect); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.hard_link_count()); + } +} + +TEST_CASE(error_reporting) { + using namespace fs; + + scoped_test_env env; + + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_out_of_dir = env.create_file("file2", 101); + const path sym_out_of_dir = env.create_symlink("dir/file", "sym"); + const path sym_in_dir = env.create_symlink("file2", "dir/sym2"); + + const perms old_perms = status(dir).permissions(); + + // test a file which doesn't exist + { + directory_entry ent; + + std::error_code ec = GetTestEC(); + ent.assign(StaticEnv::DNE, ec); + TEST_CHECK(ec); + TEST_REQUIRE(ent.path() == StaticEnv::DNE); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ExceptionChecker Checker(StaticEnv::DNE, + std::errc::no_such_file_or_directory, + "directory_entry::hard_link_count"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count()); + } + // test a dead symlink + { + directory_entry ent; + + std::error_code ec = GetTestEC(); + uintmax_t expect_bad = hard_link_count(StaticEnv::BadSymlink, ec); + TEST_CHECK(expect_bad == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ec = GetTestEC(); + ent.assign(StaticEnv::BadSymlink, ec); + TEST_REQUIRE(ent.path() == StaticEnv::BadSymlink); + TEST_CHECK(!ec); + + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == expect_bad); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ExceptionChecker Checker(StaticEnv::BadSymlink, + std::errc::no_such_file_or_directory, + "directory_entry::hard_link_count"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count()); + } + // test a file w/o appropriate permissions. + { + directory_entry ent; + uintmax_t expect_good = hard_link_count(file); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(file, ec); + TEST_REQUIRE(ent.path() == file); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(file, std::errc::permission_denied, + "hard_link_count"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.hard_link_count()); + } + permissions(dir, old_perms); + // test a symlink w/o appropriate permissions. + { + directory_entry ent; + uintmax_t expect_good = hard_link_count(sym_in_dir); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(sym_in_dir, ec); + TEST_REQUIRE(ent.path() == sym_in_dir); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied, + "hard_link_count"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.hard_link_count()); + } + permissions(dir, old_perms); + // test a symlink to a file w/o appropriate permissions + { + directory_entry ent; + uintmax_t expect_good = hard_link_count(sym_out_of_dir); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(sym_out_of_dir, ec); + TEST_REQUIRE(ent.path() == sym_out_of_dir); + TEST_CHECK(!ec); + + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == uintmax_t(-1)); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(sym_out_of_dir, std::errc::permission_denied, + "hard_link_count"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.hard_link_count()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.hard_link_count(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.hard_link_count()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/last_write_time.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/last_write_time.pass.cpp new file mode 100644 index 00000000000..afdd47a513c --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/last_write_time.pass.cpp @@ -0,0 +1,215 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// file_time_type last_write_time() const; +// file_time_type last_write_time(error_code const&) const noexcept; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "filesystem_test_helper.hpp" +#include "rapid-cxx-test.hpp" + +TEST_SUITE(directory_entry_obs_testsuite) + +TEST_CASE(signatures) { + using namespace fs; + { + const fs::directory_entry e = {}; + std::error_code ec; + static_assert(std::is_same<decltype(e.last_write_time()), file_time_type>::value, + ""); + static_assert(std::is_same<decltype(e.last_write_time(ec)), file_time_type>::value, + ""); + static_assert(noexcept(e.last_write_time()) == false, ""); + static_assert(noexcept(e.last_write_time(ec)) == true, ""); + } +} + +TEST_CASE(basic) { + using namespace fs; + + scoped_test_env env; + const path file = env.create_file("file", 42); + const path dir = env.create_dir("dir"); + const path sym = env.create_symlink("file", "sym"); + + { + directory_entry ent(file); + file_time_type expect = last_write_time(ent); + + // Remove the file to show that the results were already in the cache. + LIBCPP_ONLY(remove(file)); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == expect); + TEST_CHECK(!ec); + } + { + directory_entry ent(dir); + file_time_type expect = last_write_time(ent); + + LIBCPP_ONLY(remove(dir)); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == expect); + TEST_CHECK(!ec); + } + env.create_file("file", 99); + { + directory_entry ent(sym); + file_time_type expect = last_write_time(sym); + + std::error_code ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == expect); + TEST_CHECK(!ec); + } +} + +TEST_CASE(error_reporting) { + using namespace fs; + + scoped_test_env env; + + const path dir = env.create_dir("dir"); + const path file = env.create_file("dir/file", 42); + const path file_out_of_dir = env.create_file("file2", 101); + const path sym_out_of_dir = env.create_symlink("dir/file", "sym"); + const path sym_in_dir = env.create_symlink("file2", "dir/sym2"); + + const perms old_perms = status(dir).permissions(); + + // test a file which doesn't exist + { + directory_entry ent; + + std::error_code ec = GetTestEC(); + ent.assign(StaticEnv::DNE, ec); + TEST_REQUIRE(ent.path() == StaticEnv::DNE); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == file_time_type::min()); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ExceptionChecker Checker(StaticEnv::DNE, + std::errc::no_such_file_or_directory, + "directory_entry::last_write_time"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time()); + } + // test a dead symlink + { + directory_entry ent; + + std::error_code ec = GetTestEC(); + file_time_type expect_bad = last_write_time(StaticEnv::BadSymlink, ec); + TEST_CHECK(expect_bad == file_time_type::min()); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ec = GetTestEC(); + ent.assign(StaticEnv::BadSymlink, ec); + TEST_REQUIRE(ent.path() == StaticEnv::BadSymlink); + TEST_CHECK(!ec); + + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == expect_bad); + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); + + ExceptionChecker Checker(StaticEnv::BadSymlink, + std::errc::no_such_file_or_directory, + "directory_entry::last_write_time"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time()); + } + // test a file w/o appropriate permissions. + { + directory_entry ent; + file_time_type expect_good = last_write_time(file); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(file, ec); + TEST_REQUIRE(ent.path() == file); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == file_time_type::min()); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(file, std::errc::permission_denied, + "last_write_time"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.last_write_time()); + } + permissions(dir, old_perms); + // test a symlink w/o appropriate permissions. + { + directory_entry ent; + file_time_type expect_good = last_write_time(sym_in_dir); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(sym_in_dir, ec); + TEST_REQUIRE(ent.path() == sym_in_dir); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == file_time_type::min()); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(sym_in_dir, std::errc::permission_denied, + "last_write_time"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.last_write_time()); + } + permissions(dir, old_perms); + // test a symlink to a file w/o appropriate permissions + { + directory_entry ent; + file_time_type expect_good = last_write_time(sym_out_of_dir); + permissions(dir, perms::none); + + std::error_code ec = GetTestEC(); + ent.assign(sym_out_of_dir, ec); + TEST_REQUIRE(ent.path() == sym_out_of_dir); + TEST_CHECK(!ec); + + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == file_time_type::min()); + TEST_CHECK(ErrorIs(ec, std::errc::permission_denied)); + + ExceptionChecker Checker(sym_out_of_dir, std::errc::permission_denied, + "last_write_time"); + TEST_CHECK_THROW_RESULT(filesystem_error, Checker, ent.last_write_time()); + + permissions(dir, old_perms); + ec = GetTestEC(); + TEST_CHECK(ent.last_write_time(ec) == expect_good); + TEST_CHECK(!ec); + TEST_CHECK_NO_THROW(ent.last_write_time()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/path.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/path.pass.cpp new file mode 100644 index 00000000000..2abb13df1f8 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/path.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// const path& path() const noexcept; +// operator const path&() const noexcept; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + + +void test_path_method() { + using namespace fs; + const path p("foo/bar/baz.exe"); + const path p2("abc"); + { + directory_entry nce; + const directory_entry e(""); + static_assert(std::is_same<decltype(e.path()), const path&>::value, ""); + static_assert(std::is_same<decltype(nce.path()), const path&>::value, ""); + static_assert(noexcept(e.path()) && noexcept(nce.path()), ""); + } + { + directory_entry e(p); + path const& pref = e.path(); + assert(pref == p); + assert(&pref == &e.path()); + e.assign(p2); + assert(pref == p2); + assert(&pref == &e.path()); + } +} + +void test_path_conversion() { + using namespace fs; + const path p("foo/bar/baz.exe"); + const path p2("abc"); + { + directory_entry nce; + const directory_entry e(""); + // Check conversions exist + static_assert(std::is_convertible<directory_entry&, path const&>::value, ""); + static_assert(std::is_convertible<directory_entry const&, path const&>::value, ""); + static_assert(std::is_convertible<directory_entry &&, path const&>::value, ""); + static_assert(std::is_convertible<directory_entry const&&, path const&>::value, ""); + // Not convertible to non-const + static_assert(!std::is_convertible<directory_entry&, path&>::value, ""); + static_assert(!std::is_convertible<directory_entry const&, path&>::value, ""); + static_assert(!std::is_convertible<directory_entry &&, path&>::value, ""); + static_assert(!std::is_convertible<directory_entry const&&, path&>::value, ""); + // conversions are noexcept + static_assert(noexcept(e.operator fs::path const&()) && + noexcept(e.operator fs::path const&()), ""); + } + // const + { + directory_entry const e(p); + path const& pref = e; + assert(&pref == &e.path()); + } + // non-const + { + directory_entry e(p); + path const& pref = e; + assert(&pref == &e.path()); + + e.assign(p2); + assert(pref == p2); + assert(&pref == &e.path()); + } +} + +int main() { + test_path_method(); + test_path_conversion(); +} diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/status.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/status.pass.cpp new file mode 100644 index 00000000000..ec654468b9a --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/status.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// file_status status() const; +// file_status status(error_code const&) const noexcept; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "filesystem_test_helper.hpp" +#include "rapid-cxx-test.hpp" + +TEST_SUITE(directory_entry_status_testsuite) + +TEST_CASE(test_basic) { + using namespace fs; + { + const fs::directory_entry e("foo"); + std::error_code ec; + static_assert(std::is_same<decltype(e.status()), fs::file_status>::value, ""); + static_assert(std::is_same<decltype(e.status(ec)), fs::file_status>::value, ""); + static_assert(noexcept(e.status()) == false, ""); + static_assert(noexcept(e.status(ec)) == true, ""); + } + path TestCases[] = {StaticEnv::File, StaticEnv::Dir, StaticEnv::SymlinkToFile, + StaticEnv::DNE}; + for (const auto& p : TestCases) { + const directory_entry e(p); + std::error_code pec = GetTestEC(), eec = GetTestEC(1); + file_status ps = fs::status(p, pec); + file_status es = e.status(eec); + TEST_CHECK(ps.type() == es.type()); + TEST_CHECK(ps.permissions() == es.permissions()); + TEST_CHECK(pec == eec); + } + for (const auto& p : TestCases) { + const directory_entry e(p); + file_status ps = fs::status(p); + file_status es = e.status(); + TEST_CHECK(ps.type() == es.type()); + TEST_CHECK(ps.permissions() == es.permissions()); + } +} + +TEST_SUITE_END() diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/symlink_status.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/symlink_status.pass.cpp new file mode 100644 index 00000000000..e8850c3a7b1 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.obs/symlink_status.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <filesystem> + +// class directory_entry + +// file_status symlink_status() const; +// file_status symlink_status(error_code&) const noexcept; + +#include "filesystem_include.hpp" +#include <type_traits> +#include <cassert> + +#include "filesystem_test_helper.hpp" +#include "rapid-cxx-test.hpp" + +TEST_SUITE(directory_entry_obs_suite) + +TEST_CASE(test_signature) { + using namespace fs; + { + const directory_entry e("foo"); + std::error_code ec; + static_assert(std::is_same<decltype(e.symlink_status()), file_status>::value, ""); + static_assert(std::is_same<decltype(e.symlink_status(ec)), file_status>::value, ""); + static_assert(noexcept(e.symlink_status()) == false, ""); + static_assert(noexcept(e.symlink_status(ec)) == true, ""); + } + path TestCases[] = {StaticEnv::File, StaticEnv::Dir, StaticEnv::SymlinkToFile, + StaticEnv::DNE}; + for (const auto& p : TestCases) { + const directory_entry e(p); + std::error_code pec = GetTestEC(), eec = GetTestEC(1); + file_status ps = fs::symlink_status(p, pec); + file_status es = e.symlink_status(eec); + TEST_CHECK(ps.type() == es.type()); + TEST_CHECK(ps.permissions() == es.permissions()); + TEST_CHECK(pec == eec); + } + for (const auto& p : TestCases) { + const directory_entry e(p); + file_status ps = fs::symlink_status(p); + file_status es = e.symlink_status(); + TEST_CHECK(ps.type() == es.type()); + TEST_CHECK(ps.permissions() == es.permissions()); + } +} + +TEST_SUITE_END() |