summaryrefslogtreecommitdiffstats
path: root/libcxx/test/support/filesystem_test_helper.hpp
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2018-07-20 01:22:32 +0000
committerEric Fiselier <eric@efcs.ca>2018-07-20 01:22:32 +0000
commitc16998649e1f55c61158004f461fd629d9b8b7f9 (patch)
treec1434a61a1da354f770f4ac06994211375a84253 /libcxx/test/support/filesystem_test_helper.hpp
parent40fa4a1a559765ada93268c4d45c54b62779166b (diff)
downloadbcm5719-llvm-c16998649e1f55c61158004f461fd629d9b8b7f9.tar.gz
bcm5719-llvm-c16998649e1f55c61158004f461fd629d9b8b7f9.zip
[libc++] Implement Directory Entry Caching -- Sort of.
Summary: This patch implements directory_entry caching *almost* as specified in P0317r1. However, I explicitly chose to deviate from the standard as I'll explain below. The approach I decided to take is a fully caching one. When `refresh()` is called, the cache is populated by calls to `stat` and `lstat` as needed. During directory iteration the cache is only populated with the `file_type` as reported by `readdir`. The cache can be in the following states: * `_Empty`: There is nothing in the cache (likely due to an error) * `_IterSymlink`: Created by directory iteration when we walk onto a symlink only the symlink file type is known. * `_IterNonSymlink`: Created by directory iteration when we walk onto a non-symlink. Both the regular file type and symlink file type are known. * `_RefreshSymlink` and `_RefreshNonSymlink`: A full cache created by `refresh()`. This case includes dead symlinks. * `_RefreshSymlinkUnresolved`: A partial cache created by refresh when we fail to resolve the file pointed to by a symlink (likely due to permissions). Symlink attributes are cached, but attributes about the linked entity are not. As mentioned, this implementation purposefully deviates from the standard. According to some readings of the specification, and the Windows filesystem implementation, the constructors and modifiers which don't pass an `error_code` must throw when the `directory_entry` points to a entity which doesn't exist. or when attribute resolution fails for another reason. @BillyONeal has proposed a more reasonable set of requirements, where modifiers other than refresh ignore errors. This is the behavior libc++ currently implements, with the expectation some form of the new language will be accepted into the standard. Some additional semantics which differ from the Windows implementation: 1. `refresh` will not throw when the entry doesn't exist. In this case we can still meet the functions specification, so we don't treat it as an error. 2. We don't clear the path name when a constructor fails via refresh (this will hopefully be changed in the standard as well). It should be noted that libstdc++'s current implementation has the same behavior as libc++, except for point (2). If the changes to the specification don't get accepted, we'll be able to make the changes later. [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0317r1.html Reviewers: mclow.lists, gromer, ldionne, aaron.ballman Subscribers: BillyONeal, christof, cfe-commits Differential Revision: https://reviews.llvm.org/D49530 llvm-svn: 337516
Diffstat (limited to 'libcxx/test/support/filesystem_test_helper.hpp')
-rw-r--r--libcxx/test/support/filesystem_test_helper.hpp60
1 files changed, 58 insertions, 2 deletions
diff --git a/libcxx/test/support/filesystem_test_helper.hpp b/libcxx/test/support/filesystem_test_helper.hpp
index 5a8a32a406c..e3f46a16af3 100644
--- a/libcxx/test/support/filesystem_test_helper.hpp
+++ b/libcxx/test/support/filesystem_test_helper.hpp
@@ -8,6 +8,9 @@
#include <fstream>
#include <random>
#include <chrono>
+#include <vector>
+
+#include "rapid-cxx-test.hpp"
// static test helpers
@@ -381,8 +384,39 @@ bool checkCollectionsEqualBackwards(
// We often need to test that the error_code was cleared if no error occurs
// this function returns an error_code which is set to an error that will
// never be returned by the filesystem functions.
-inline std::error_code GetTestEC() {
- return std::make_error_code(std::errc::address_family_not_supported);
+inline std::error_code GetTestEC(unsigned Idx = 0) {
+ using std::errc;
+ auto GetErrc = [&]() {
+ switch (Idx) {
+ case 0:
+ return errc::address_family_not_supported;
+ case 1:
+ return errc::address_not_available;
+ case 2:
+ return errc::address_in_use;
+ case 3:
+ return errc::argument_list_too_long;
+ default:
+ assert(false && "Idx out of range");
+ std::abort();
+ }
+ };
+ return std::make_error_code(GetErrc());
+}
+
+inline bool ErrorIsImp(const std::error_code& ec,
+ std::vector<std::errc> const& errors) {
+ for (auto errc : errors) {
+ if (ec == std::make_error_code(errc))
+ return true;
+ }
+ return false;
+}
+
+template <class... ErrcT>
+inline bool ErrorIs(const std::error_code& ec, std::errc First, ErrcT... Rest) {
+ std::vector<std::errc> errors = {First, Rest...};
+ return ErrorIsImp(ec, errors);
}
// Provide our own Sleep routine since std::this_thread::sleep_for is not
@@ -403,4 +437,26 @@ inline bool PathEq(fs::path const& LHS, fs::path const& RHS) {
return LHS.native() == RHS.native();
}
+struct ExceptionChecker {
+ std::vector<std::errc> expected_err_list;
+ fs::path expected_path1;
+ fs::path expected_path2;
+
+ template <class... ErrcT>
+ explicit ExceptionChecker(fs::path p, std::errc first_err, ErrcT... rest_err)
+ : expected_err_list({first_err, rest_err...}), expected_path1(p) {}
+
+ template <class... ErrcT>
+ explicit ExceptionChecker(fs::path p1, fs::path p2, std::errc first_err,
+ ErrcT... rest_err)
+ : expected_err_list({first_err, rest_err...}), expected_path1(p1),
+ expected_path2(p2) {}
+
+ void operator()(fs::filesystem_error const& Err) const {
+ TEST_CHECK(ErrorIsImp(Err.code(), expected_err_list));
+ TEST_CHECK(Err.path1() == expected_path1);
+ TEST_CHECK(Err.path2() == expected_path2);
+ }
+};
+
#endif /* FILESYSTEM_TEST_HELPER_HPP */
OpenPOWER on IntegriCloud