diff --git a/include/asyncpp/core/future.h b/include/asyncpp/core/future.h index b2f6357..575a5ef 100644 --- a/include/asyncpp/core/future.h +++ b/include/asyncpp/core/future.h @@ -6,6 +6,7 @@ #include "future.pre.h" #include "future/map.h" +#include "future/lazy.h" #include "future/and_then.h" namespace asyncpp diff --git a/include/asyncpp/core/future.inl b/include/asyncpp/core/future.inl index 6763be1..9834fb1 100644 --- a/include/asyncpp/core/future.inl +++ b/include/asyncpp/core/future.inl @@ -3,6 +3,7 @@ #include "future.h" #include "future/map.inl" +#include "future/lazy.inl" #include "future/and_then.inl" #ifdef asyncpp_timing diff --git a/include/asyncpp/core/future/and_then.h b/include/asyncpp/core/future/and_then.h index 8cf2ce2..63d441b 100644 --- a/include/asyncpp/core/future/and_then.h +++ b/include/asyncpp/core/future/and_then.h @@ -27,10 +27,10 @@ namespace __future { using base_future_type = base_future; using result_type = typename base_future_type::result_type; - public: - lambda_type lambda; - first_future_type first; - second_future_type_ptr second; + private: + lambda_type _lambda; + first_future_type _first; + second_future_type_ptr _second; public: /** diff --git a/include/asyncpp/core/future/and_then.inl b/include/asyncpp/core/future/and_then.inl index df34ba7..4e1d737 100644 --- a/include/asyncpp/core/future/and_then.inl +++ b/include/asyncpp/core/future/and_then.inl @@ -17,8 +17,8 @@ namespace __future { ::and_then_impl( X_future&& p_first, X_lambda&& p_lambda) - : first (std::forward(p_first)) - , lambda(std::forward(p_lambda)) + : _first (std::forward(p_first)) + , _lambda(std::forward(p_lambda)) { } template< @@ -30,17 +30,17 @@ namespace __future { { while (true) { - if (second) + if (_second) { - return second->poll(); + return _second->poll(); } else { - auto r = first.poll(); + auto r = _first.poll(); if (!r) return result_type::not_ready(); - second = std::make_unique(r.call(lambda)); + _second = std::make_unique(r.call(_lambda)); } } } diff --git a/include/asyncpp/core/future/lazy.h b/include/asyncpp/core/future/lazy.h new file mode 100644 index 0000000..552021e --- /dev/null +++ b/include/asyncpp/core/future/lazy.h @@ -0,0 +1,64 @@ +#pragma once + +#include "../future.pre.h" + +namespace asyncpp +{ + + namespace __future + { + + template + struct lazy_impl final : + public base_future< + decltype(std::declval()()), + lazy_impl + > + { + public: + using lambda_type = T_lambda; + using value_type = decltype(std::declval()()); + using this_type = lazy_impl; + using base_future_type = base_future; + using result_type = typename base_future_type::result_type; + + private: + lambda_type _lambda; + + public: + /** + * @brief Constructor. + */ + template + inline lazy_impl( + X_lambda&& p_lambda); + + public: /* future */ + /** + * @brief Poll the result from the future. + */ + template + inline auto poll() + -> std::enable_if_t< + std::is_void_v, + result_type>; + + /** + * @brief Poll the result from the future. + */ + template + inline auto poll() + -> std::enable_if_t< + !std::is_void_v, + result_type>; + }; + + } + + /** + * @brief Create a lazy evaluated future. + */ + template + inline auto lazy(X_lambda&& p_lambda); + +} diff --git a/include/asyncpp/core/future/lazy.inl b/include/asyncpp/core/future/lazy.inl new file mode 100644 index 0000000..60b5f03 --- /dev/null +++ b/include/asyncpp/core/future/lazy.inl @@ -0,0 +1,53 @@ +#pragma once + +#include "lazy.h" + +namespace asyncpp +{ + + namespace __future + { + + /* lazy_impl */ + + template + template + lazy_impl::lazy_impl( + X_lambda&& p_lambda) + : _lambda(std::forward(p_lambda)) + { } + + template + template + inline auto lazy_impl + ::poll() + -> std::enable_if_t< + std::is_void_v, + result_type> + { + _lambda(); + return result_type::ready(); + } + + template + template + inline auto lazy_impl + ::poll() + -> std::enable_if_t< + !std::is_void_v, + result_type> + { + return result_type::ready(_lambda()); + } + } + + template + inline auto lazy(X_lambda&& p_lambda) + { + using lambda_type = X_lambda; + using lazy_type = __future::lazy_impl; + + return lazy_type(std::forward(p_lambda)); + } + +} diff --git a/include/asyncpp/core/future/map.h b/include/asyncpp/core/future/map.h index eed3ede..979c740 100644 --- a/include/asyncpp/core/future/map.h +++ b/include/asyncpp/core/future/map.h @@ -23,9 +23,9 @@ namespace __future { using base_future_type = base_future; using result_type = typename base_future_type::result_type; - public: - future_type future; - lambda_type lambda; + private: + future_type _future; + lambda_type _lambda; public: /** diff --git a/include/asyncpp/core/future/map.inl b/include/asyncpp/core/future/map.inl index bdc6c39..c03d292 100644 --- a/include/asyncpp/core/future/map.inl +++ b/include/asyncpp/core/future/map.inl @@ -17,8 +17,8 @@ namespace __future { ::map_impl( X_future&& p_future, X_lambda&& p_lambda) - : future(std::forward(p_future)) - , lambda(std::forward(p_lambda)) + : _future(std::forward(p_future)) + , _lambda(std::forward(p_lambda)) { } template< @@ -28,9 +28,9 @@ namespace __future { map_impl ::poll() { - auto r = future.poll(); + auto r = _future.poll(); return r - ? result_type::ready(r.call(lambda)) + ? result_type::ready(r.call(_lambda)) : result_type::not_ready(); } diff --git a/include/asyncpp/core/stream.h b/include/asyncpp/core/stream.h index 46a0d2a..8271f14 100644 --- a/include/asyncpp/core/stream.h +++ b/include/asyncpp/core/stream.h @@ -5,8 +5,6 @@ #include "result.h" #include "stream.pre.h" -#include "stream/for_each.h" - namespace asyncpp { @@ -47,6 +45,44 @@ namespace asyncpp template inline auto for_each(X_lambda&& p_lambda) &&; + public: + /** + * @brief Transforms the stream from one type to another type + * by executing the passed lambda for each value. + */ + template + inline auto map(X_lambda&& p_lambda) const &; + + /** + * @brief Transforms the stream from one type to another type + * by executing the passed lambda for each value. + */ + template + inline auto map(X_lambda&& p_lambda) &; + + /** + * @brief Transforms the stream from one type to another type + * by executing the passed lambda for each value. + */ + template + inline auto map(X_lambda&& p_lambda) &&; + + public: + /** + * @brief Flatten the stream of streams to a single stream. + */ + inline auto flatten() const &; + + /** + * @brief Flatten the stream of streams to a single stream. + */ + inline auto flatten() &; + + /** + * @brief Flatten the stream of streams to a single stream. + */ + inline auto flatten() &&; + #ifdef asyncpp_timing public: /** diff --git a/include/asyncpp/core/stream.inl b/include/asyncpp/core/stream.inl index bb62afe..9eebd0f 100644 --- a/include/asyncpp/core/stream.inl +++ b/include/asyncpp/core/stream.inl @@ -2,6 +2,8 @@ #include "stream.h" +#include "stream/map.inl" +#include "stream/flatten.inl" #include "stream/for_each.inl" #ifdef asyncpp_timing @@ -67,6 +69,106 @@ namespace asyncpp std::forward(p_lambda)); } + /* base_stream::map */ + + template< + typename T_value, + typename T_derived> + template< + typename X_lambda> + auto base_stream + ::map(X_lambda&& p_lambda) const & + { + using lambda_type = X_lambda; + using map_type = __stream::map_impl; + + auto& self = static_cast(*this); + + return map_type( + std::forward(self), + std::forward(p_lambda)); + } + + template< + typename T_value, + typename T_derived> + template< + typename X_lambda> + auto base_stream + ::map(X_lambda&& p_lambda) & + { + using lambda_type = X_lambda; + using map_type = __stream::map_impl; + + auto& self = static_cast(*this); + + return map_type( + std::forward(self), + std::forward(p_lambda)); + } + + template< + typename T_value, + typename T_derived> + template< + typename X_lambda> + auto base_stream + ::map(X_lambda&& p_lambda) && + { + using lambda_type = X_lambda; + using map_type = __stream::map_impl; + + auto& self = static_cast(*this); + + return map_type( + std::forward(self), + std::forward(p_lambda)); + } + + /* base_stream::flatten */ + + template< + typename T_value, + typename T_derived> + auto base_stream + ::flatten() const & + { + using flatten_type = __stream::flatten_impl; + + auto& self = static_cast(*this); + + return flatten_type( + std::forward(self)); + } + + template< + typename T_value, + typename T_derived> + auto base_stream + ::flatten() & + { + using flatten_type = __stream::flatten_impl; + + auto& self = static_cast(*this); + + return flatten_type( + std::forward(self)); + } + + template< + typename T_value, + typename T_derived> + auto base_stream + ::flatten() && + { + using flatten_type = __stream::flatten_impl; + + auto& self = static_cast(*this); + + return flatten_type( + std::forward(self)); + } + /* base_stream::timeout */ #ifdef asyncpp_timing diff --git a/include/asyncpp/core/stream/flatten.h b/include/asyncpp/core/stream/flatten.h new file mode 100644 index 0000000..9c61190 --- /dev/null +++ b/include/asyncpp/core/stream/flatten.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include + +namespace asyncpp { +namespace __stream { + + template< + typename T_stream> + struct flatten_impl final : + public base_stream< + typename T_stream::value_type::value_type, + flatten_impl + > + { + public: + using stream_type = T_stream; + using inner_stream_type = typename stream_type::value_type; + using inner_stream_ptr_u = std::unique_ptr; + using value_type = typename inner_stream_type::value_type; + using this_type = flatten_impl; + using base_stream_type = base_stream; + using result_type = typename base_stream_type::result_type; + + private: + stream_type _stream; + inner_stream_ptr_u _inner; + + public: + /** + * @brief Constructor. + */ + template< + typename X_stream> + inline flatten_impl( + X_stream&& p_stream); + + public: /* future */ + /** + * @brief Poll the result from the future. + */ + inline result_type poll(); + }; + +} } diff --git a/include/asyncpp/core/stream/flatten.inl b/include/asyncpp/core/stream/flatten.inl new file mode 100644 index 0000000..aa1b6d5 --- /dev/null +++ b/include/asyncpp/core/stream/flatten.inl @@ -0,0 +1,49 @@ +#pragma once + +#include "flatten.h" + +namespace asyncpp { +namespace __stream { + + /* flatten_impl */ + + template< + typename T_stream> + template< + typename X_stream> + flatten_impl::flatten_impl( + X_stream&& p_stream) + : _stream (std::forward(p_stream)) + , _inner () + { } + + template< + typename T_stream> + typename flatten_impl::result_type + flatten_impl + ::poll() + { + while (true) + { + if (_inner) + { + auto r = _inner->poll(); + + if (!r.is_done()) + return r; + + _inner.reset(); + } + + auto r = _stream.poll(); + if (r.is_done()) + return result_type::done(); + + if (r.is_not_ready()) + return result_type::not_ready(); + + _inner = std::make_unique(std::move(*r)); + } + } + +} } diff --git a/include/asyncpp/core/stream/for_each.h b/include/asyncpp/core/stream/for_each.h index 491dfed..d31265e 100644 --- a/include/asyncpp/core/stream/for_each.h +++ b/include/asyncpp/core/stream/for_each.h @@ -22,9 +22,9 @@ namespace __stream { using base_future_type = base_future; using result_type = typename base_future_type::result_type; - public: - stream_type stream; - lambda_type lambda; + private: + stream_type _stream; + lambda_type _lambda; public: /** diff --git a/include/asyncpp/core/stream/for_each.inl b/include/asyncpp/core/stream/for_each.inl index 1ad6581..d4e2900 100644 --- a/include/asyncpp/core/stream/for_each.inl +++ b/include/asyncpp/core/stream/for_each.inl @@ -17,8 +17,8 @@ namespace __stream { ::for_each_impl( X_stream&& p_stream, X_lambda&& p_lambda) - : stream(std::forward(p_stream)) - , lambda(std::forward(p_lambda)) + : _stream(std::forward(p_stream)) + , _lambda(std::forward(p_lambda)) { } template< @@ -30,14 +30,14 @@ namespace __stream { { while (true) { - auto r = stream.poll(); + auto r = _stream.poll(); if (r.is_done()) return result_type::ready(); if (r.is_not_ready()) return result_type::not_ready(); - r.call(lambda); + r.call(_lambda); } } diff --git a/include/asyncpp/core/stream/map.h b/include/asyncpp/core/stream/map.h new file mode 100644 index 0000000..d20d1c4 --- /dev/null +++ b/include/asyncpp/core/stream/map.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +namespace asyncpp { +namespace __stream { + + template< + typename T_stream, + typename T_lambda> + struct map_impl final : + public base_stream< + decltype(std::declval()(std::declval())), + map_impl + > + { + public: + using stream_type = T_stream; + using lambda_type = T_lambda; + using inner_value_type = typename stream_type::value_type; + using value_type = decltype(std::declval()(std::declval())); + using this_type = map_impl; + using base_stream_type = base_stream; + using result_type = typename base_stream_type::result_type; + + private: + stream_type _stream; + lambda_type _lambda; + + public: + /** + * @brief Constructor. + */ + template< + typename X_stream, + typename X_lambda> + inline map_impl( + X_stream&& p_stream, + X_lambda&& p_lambda); + + public: /* future */ + /** + * @brief Poll the result from the future. + */ + inline result_type poll(); + }; + +} } diff --git a/include/asyncpp/core/stream/map.inl b/include/asyncpp/core/stream/map.inl new file mode 100644 index 0000000..3235abe --- /dev/null +++ b/include/asyncpp/core/stream/map.inl @@ -0,0 +1,40 @@ +#pragma once + +#include "map.h" + +namespace asyncpp { +namespace __stream { + + /* map_impl */ + + template< + typename T_stream, + typename T_lambda> + template< + typename X_stream, + typename X_lambda> + map_impl::map_impl( + X_stream&& p_stream, + X_lambda&& p_lambda) + : _stream(std::forward(p_stream)) + , _lambda(std::forward(p_lambda)) + { } + + template< + typename T_stream, + typename T_lambda> + typename map_impl::result_type + map_impl + ::poll() + { + auto r = _stream.poll(); + if (r.is_done()) + return result_type::done(); + + if (r.is_ready()) + return result_type::ready(r.call(_lambda)); + + return result_type::not_ready(); + } + +} } diff --git a/include/asyncpp/fs.h b/include/asyncpp/fs.h new file mode 100644 index 0000000..5d95a8e --- /dev/null +++ b/include/asyncpp/fs.h @@ -0,0 +1,5 @@ +#pragma once + +#include "fs/directory.h" + +#include "fs/directory.inl" diff --git a/include/asyncpp/fs/directory.h b/include/asyncpp/fs/directory.h new file mode 100644 index 0000000..88e6c0c --- /dev/null +++ b/include/asyncpp/fs/directory.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include + +#include +#include + +namespace asyncpp { +namespace fs { + + /** + * @brief Create future to read the content of a directory. + */ + inline auto read_dir(const cppfs::path& p_path); + + /** + * @brief Create future to read the content of a directory including the subdirectories. + */ + inline auto read_dir_all(const cppfs::path& p_path); + + /** + * @brief Create a new future to create a directory. + */ + inline auto create_dir(const cppfs::path& p_path); + + /** + * @brief Create a new future to create a directory and all it's parent directories. + */ + inline auto create_dir_all(const cppfs::path& p_path); + + /** + * @brief Create a new future to remove an empty directory. + */ + inline auto remove_dir(const cppfs::path& p_path); + + /** + * @brief Create a new future to remove a directory and all it's content. + */ + inline auto remove_dir_all(const cppfs::path& p_path); + +} } diff --git a/include/asyncpp/fs/directory.inl b/include/asyncpp/fs/directory.inl new file mode 100644 index 0000000..975f4e3 --- /dev/null +++ b/include/asyncpp/fs/directory.inl @@ -0,0 +1,167 @@ +#pragma once + +#include + +#include + +#include "directory.h" + +namespace asyncpp { +namespace fs { + + namespace __impl + { + + struct read_dir_impl + : public base_stream< + cppfs::directory::entry, + read_dir_impl> + { + public: + using value_type = cppfs::directory::entry; + using this_type = read_dir_impl; + using base_future_type = base_stream; + using result_type = typename base_future_type::result_type; + + private: + cppfs::directory::iterator _it; + cppfs::directory::iterator _end; + + public: + inline read_dir_impl( + const cppfs::path& p_path) + { + cppfs::directory d(p_path); + if (d.exists()) + { + _it = d.begin(); + _end = d.end(); + } + } + + public: + inline result_type poll() + { + if (_it == _end) + return result_type::done(); + + auto ret = result_type::ready(*_it); + ++_it; + return ret; + } + }; + + struct read_dir_all_impl + : public base_stream< + cppfs::directory::entry, + read_dir_all_impl> + { + public: + using value_type = cppfs::directory::entry; + using this_type = read_dir_impl; + using base_future_type = base_stream; + using result_type = typename base_future_type::result_type; + + private: + struct entry + { + cppfs::directory::iterator it; + cppfs::directory::iterator end; + }; + + using entry_stack = std::vector; + + entry_stack _stack; + + public: + inline read_dir_all_impl( + const cppfs::path& p_path) + { + cppfs::directory d(p_path); + if (d.exists()) + { + _stack.emplace_back(entry { + d.begin(), + d.end() + }); + } + } + + public: + inline result_type poll() + { + while (true) + { + if (_stack.empty()) + return result_type::done(); + + auto& e = _stack.back(); + if (e.it == e.end) + { + _stack.pop_back(); + continue; + } + + auto ret = result_type::ready(std::move(*e.it)); + cppfs::directory d(e.it->path); + + ++e.it; + + if (d.exists()) + { + _stack.emplace_back(entry { + d.begin(), + d.end(), + }); + } + + return ret; + } + } + }; + + } + + auto read_dir(const cppfs::path& p_path) + { + return __impl::read_dir_impl(p_path); + } + + auto read_dir_all(const cppfs::path& p_path) + { + return __impl::read_dir_all_impl(p_path); + } + + auto create_dir(const cppfs::path& p_path) + { + return lazy([d = cppfs::directory(p_path)]{ + if (!d.exists()) + d.create(false); + }); + } + + auto create_dir_all(const cppfs::path& p_path) + { + return lazy([d = cppfs::directory(p_path)]{ + if (!d.exists()) + d.create(true); + }); + } + + auto remove_dir(const cppfs::path& p_path) + { + return lazy([d = cppfs::directory(p_path)]{ + if (d.exists()) + d.remove(false); + }); + } + + auto remove_dir_all(const cppfs::path& p_path) + { + return lazy([d = cppfs::directory(p_path)]{ + if (d.exists()) + d.remove(true); + }); + } + +} } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afd6aa9..975a22a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ Include ( cotire OPTIONAL RESULT_VARIABLE HAS Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) +Find_Package ( cppfs REQUIRED ) Find_Package ( cppcore REQUIRED ) # Interface Library ############################################################################### @@ -16,6 +17,7 @@ Target_Include_Directories ( asyncpp $ ) Target_Link_Libraries ( asyncpp INTERFACE + cppfs::cppfs cppcore::cppcore ) # Install ######################################################################################### diff --git a/test/asyncpp/core/future_tests.cpp b/test/asyncpp/core/future_tests.cpp index 3901406..6a578c1 100644 --- a/test/asyncpp/core/future_tests.cpp +++ b/test/asyncpp/core/future_tests.cpp @@ -72,5 +72,21 @@ TEST(future_tests, and_then) auto r = f.poll(); ASSERT_TRUE(r); ASSERT_EQ (5, *r); - ASSERT_EQ (2, f.first._count); +} + +TEST(future_tests, lazy) +{ + int i = 1; + auto f = lazy([&]{ + ++i; + return i + 1; + }); + + ASSERT_EQ(i, 1); + + auto r = f.poll(); + + ASSERT_TRUE(r); + ASSERT_EQ (2, i); + ASSERT_EQ (3, *r); } diff --git a/test/asyncpp/core/stream_tests.cpp b/test/asyncpp/core/stream_tests.cpp index e489ca0..b9e2213 100644 --- a/test/asyncpp/core/stream_tests.cpp +++ b/test/asyncpp/core/stream_tests.cpp @@ -73,3 +73,72 @@ TEST(stream_tests, for_each) auto r = f.poll(); ASSERT_TRUE(r); } + +TEST(stream_tests, map) +{ + delay d { 5, 0, 0 }; + auto s = d + .map([](int i){ + return std::to_string(i); + }); + + auto r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, "1"); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, "2"); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, "3"); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, "4"); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, "5"); + + r = s.poll(); + ASSERT_TRUE(r.is_done()); +} + +TEST(stream_tests, flatten) +{ + delay d { 3, 0, 0 }; + auto s = d + .map([](int i){ + return delay { i * 100 + 2, 0, i * 100 }; + }) + .flatten(); + + auto r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, 101); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, 102); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, 201); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, 202); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, 301); + + r = s.poll(); + ASSERT_TRUE(r); + ASSERT_EQ (*r, 302); + + r = s.poll(); + ASSERT_TRUE(r.is_done()); +} diff --git a/test/asyncpp/fs/directory_tests.cpp b/test/asyncpp/fs/directory_tests.cpp new file mode 100644 index 0000000..679bfe4 --- /dev/null +++ b/test/asyncpp/fs/directory_tests.cpp @@ -0,0 +1,210 @@ +#include + +#include +#include + +using namespace ::testing; +using namespace ::asyncpp; + +struct auto_remove_dir + : public cppfs::directory +{ +public: + using cppfs::directory::directory; + + inline ~auto_remove_dir() + { + if (exists()) + remove(true); + } +}; + +class directory_tests + : public ::testing::Test +{ +protected: + static const std::string& path_test_dir() + { + static const std::string value("/tmp/asyncpp/test"); + return value; + } + + static const std::string& path_test_dir_single() + { + static const std::string value("/tmp/asyncpp/test/single"); + return value; + } + + static const std::string& path_test_dir_parent() + { + static const std::string value("/tmp/asyncpp/test/parent"); + return value; + } + + static const std::string& path_test_dir_child() + { + static const std::string value("/tmp/asyncpp/test/parent/child"); + return value; + } + + void SetUp() override + { + cppfs::directory d(path_test_dir()); + if (!d.exists()) + d.create(true); + } + + void TearDown() override + { + cppfs::directory d(path_test_dir()); + if (d.exists()) + d.remove(true); + } +}; + +TEST_F(directory_tests, read_dir) +{ + using namespace cppfs; + using namespace std::string_literals; + + auto s = fs::read_dir("."s); + auto v = std::vector(); + auto r = decltype(s)::result_type::not_ready(); + + while ((r = s.poll()).is_ready()) + v.emplace_back(r->path.parts().back()); + + ASSERT_TRUE(r.is_done()); + + std::sort(v.begin(), v.end(), cppcore::op_invariant_string_less { }); + EXPECT_EQ(v, std::vector({ + "asyncpp", + "CMakeLists.txt", + "helper", + })); +} + +TEST_F(directory_tests, read_dir_all) +{ + using namespace cppfs; + using namespace std::string_literals; + + auto s = fs::read_dir_all("."s); + auto r = decltype(s)::result_type::not_ready(); + + auto entries = std::vector(); + while ((r = s.poll()).is_ready()) + entries.emplace_back(*r); + + ASSERT_TRUE(r.is_done()); + + std::sort(entries.begin(), entries.end()); + + std::vector paths; + paths.reserve(entries.size()); + std::transform( + entries.begin(), + entries.end(), + std::back_inserter(paths), + [](auto& e) { + auto s = std::to_string(static_cast(e.type)) + e.path.str(); + return s; + }); + + EXPECT_EQ(paths, std::vector({ + "1./asyncpp", + "1./asyncpp/core", + "2./asyncpp/core/future_tests.cpp", + "2./asyncpp/core/result_tests.cpp", + "2./asyncpp/core/stream_tests.cpp", + "2./asyncpp/core/task_tests.cpp", + "1./asyncpp/executor", + "2./asyncpp/executor/current_thread_tests.cpp", + "1./asyncpp/fs", + "2./asyncpp/fs/directory_tests.cpp", + "1./asyncpp/timing", + "2./asyncpp/timing/delay_tests.cpp", + "2./asyncpp/timing/interval_tests.cpp", + "2./asyncpp/timing/timeout_tests.cpp", + "2./asyncpp/timing/timer_tests.cpp", + "1./helper", + "2./helper/now_mock.h", + "2./helper/runtime_mock.h", + "2./helper/test_delay.h", + "2./CMakeLists.txt", + })); +} + +TEST_F(directory_tests, create_dir) +{ + auto f = + lazy([path=path_test_dir_single()]{ + return path; + }) + .and_then(fs::create_dir); + + auto_remove_dir d(path_test_dir_single()); + + ASSERT_FALSE(d.exists()); + + auto r = f.poll(); + + ASSERT_TRUE (r); + ASSERT_TRUE (d.exists()); +} + +TEST_F(directory_tests, create_dir_all) +{ + auto f = + lazy([path=path_test_dir_child()]{ + return path; + }) + .and_then(fs::create_dir_all); + + auto_remove_dir d(path_test_dir_child()); + + ASSERT_FALSE(d.exists()); + + auto r = f.poll(); + + ASSERT_TRUE (r); + ASSERT_TRUE (d.exists()); +} + +TEST_F(directory_tests, remove_dir) +{ + auto f = + lazy([path=path_test_dir_single()]{ + return path; + }) + .and_then(fs::remove_dir); + + auto_remove_dir d(path_test_dir_single()); + d.create(true); + + ASSERT_TRUE (d.exists()); + + auto r = f.poll(); + + ASSERT_TRUE (r); + ASSERT_FALSE(d.exists()); +} + +TEST_F(directory_tests, remove_dir_all) +{ + auto f = + lazy([path=path_test_dir_parent()]{ + return path; + }) + .and_then(fs::remove_dir_all); + + auto_remove_dir d(path_test_dir_child()); + d.create(true); + + ASSERT_TRUE (d.exists()); + + auto r = f.poll(); + + ASSERT_TRUE (r); + ASSERT_FALSE(d.exists()); +}