Преглед на файлове

* Implemented new stream features: 'map', 'flatten'

* Implemented new future features: 'lazy'
* Implemented new module 'fs' with directory operations
master
bergmann преди 4 години
родител
ревизия
13ef3253dc
променени са 23 файла, в които са добавени 980 реда и са изтрити 27 реда
  1. +1
    -0
      include/asyncpp/core/future.h
  2. +1
    -0
      include/asyncpp/core/future.inl
  3. +4
    -4
      include/asyncpp/core/future/and_then.h
  4. +6
    -6
      include/asyncpp/core/future/and_then.inl
  5. +64
    -0
      include/asyncpp/core/future/lazy.h
  6. +53
    -0
      include/asyncpp/core/future/lazy.inl
  7. +3
    -3
      include/asyncpp/core/future/map.h
  8. +4
    -4
      include/asyncpp/core/future/map.inl
  9. +38
    -2
      include/asyncpp/core/stream.h
  10. +102
    -0
      include/asyncpp/core/stream.inl
  11. +47
    -0
      include/asyncpp/core/stream/flatten.h
  12. +49
    -0
      include/asyncpp/core/stream/flatten.inl
  13. +3
    -3
      include/asyncpp/core/stream/for_each.h
  14. +4
    -4
      include/asyncpp/core/stream/for_each.inl
  15. +48
    -0
      include/asyncpp/core/stream/map.h
  16. +40
    -0
      include/asyncpp/core/stream/map.inl
  17. +5
    -0
      include/asyncpp/fs.h
  18. +43
    -0
      include/asyncpp/fs/directory.h
  19. +167
    -0
      include/asyncpp/fs/directory.inl
  20. +2
    -0
      src/CMakeLists.txt
  21. +17
    -1
      test/asyncpp/core/future_tests.cpp
  22. +69
    -0
      test/asyncpp/core/stream_tests.cpp
  23. +210
    -0
      test/asyncpp/fs/directory_tests.cpp

+ 1
- 0
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


+ 1
- 0
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


+ 4
- 4
include/asyncpp/core/future/and_then.h Целия файл

@@ -27,10 +27,10 @@ namespace __future {
using base_future_type = base_future<value_type, this_type>;
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:
/**


+ 6
- 6
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<X_future>(p_first))
, lambda(std::forward<X_lambda>(p_lambda))
: _first (std::forward<X_future>(p_first))
, _lambda(std::forward<X_lambda>(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<second_future_type>(r.call(lambda));
_second = std::make_unique<second_future_type>(r.call(_lambda));
}
}
}


+ 64
- 0
include/asyncpp/core/future/lazy.h Целия файл

@@ -0,0 +1,64 @@
#pragma once

#include "../future.pre.h"

namespace asyncpp
{

namespace __future
{

template<typename T_lambda>
struct lazy_impl final :
public base_future<
decltype(std::declval<T_lambda>()()),
lazy_impl<T_lambda>
>
{
public:
using lambda_type = T_lambda;
using value_type = decltype(std::declval<lambda_type>()());
using this_type = lazy_impl<lambda_type>;
using base_future_type = base_future<value_type, this_type>;
using result_type = typename base_future_type::result_type;

private:
lambda_type _lambda;

public:
/**
* @brief Constructor.
*/
template<typename X_lambda>
inline lazy_impl(
X_lambda&& p_lambda);

public: /* future */
/**
* @brief Poll the result from the future.
*/
template<typename X = value_type>
inline auto poll()
-> std::enable_if_t<
std::is_void_v<X>,
result_type>;

/**
* @brief Poll the result from the future.
*/
template<typename X = value_type>
inline auto poll()
-> std::enable_if_t<
!std::is_void_v<X>,
result_type>;
};

}

/**
* @brief Create a lazy evaluated future.
*/
template<typename X_lambda>
inline auto lazy(X_lambda&& p_lambda);

}

+ 53
- 0
include/asyncpp/core/future/lazy.inl Целия файл

@@ -0,0 +1,53 @@
#pragma once

#include "lazy.h"

namespace asyncpp
{

namespace __future
{

/* lazy_impl */

template<typename T_lambda>
template<typename X_lambda>
lazy_impl<T_lambda>::lazy_impl(
X_lambda&& p_lambda)
: _lambda(std::forward<X_lambda>(p_lambda))
{ }

template<typename T_lambda>
template<typename X>
inline auto lazy_impl<T_lambda>
::poll()
-> std::enable_if_t<
std::is_void_v<X>,
result_type>
{
_lambda();
return result_type::ready();
}

template<typename T_lambda>
template<typename X>
inline auto lazy_impl<T_lambda>
::poll()
-> std::enable_if_t<
!std::is_void_v<X>,
result_type>
{
return result_type::ready(_lambda());
}
}

template<typename X_lambda>
inline auto lazy(X_lambda&& p_lambda)
{
using lambda_type = X_lambda;
using lazy_type = __future::lazy_impl<lambda_type>;

return lazy_type(std::forward<X_lambda>(p_lambda));
}

}

+ 3
- 3
include/asyncpp/core/future/map.h Целия файл

@@ -23,9 +23,9 @@ namespace __future {
using base_future_type = base_future<value_type, this_type>;
using result_type = typename base_future_type::result_type;

public:
future_type future;
lambda_type lambda;
private:
future_type _future;
lambda_type _lambda;

public:
/**


+ 4
- 4
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<X_future>(p_future))
, lambda(std::forward<X_lambda>(p_lambda))
: _future(std::forward<X_future>(p_future))
, _lambda(std::forward<X_lambda>(p_lambda))
{ }

template<
@@ -28,9 +28,9 @@ namespace __future {
map_impl<T_future, T_lambda>
::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();
}



+ 38
- 2
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<typename X_lambda>
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<typename X_lambda>
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<typename X_lambda>
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<typename X_lambda>
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:
/**


+ 102
- 0
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<X_lambda>(p_lambda));
}

/* base_stream::map */

template<
typename T_value,
typename T_derived>
template<
typename X_lambda>
auto base_stream<T_value, T_derived>
::map(X_lambda&& p_lambda) const &
{
using lambda_type = X_lambda;
using map_type = __stream::map_impl<derived_type, lambda_type>;

auto& self = static_cast<derived_type const &>(*this);

return map_type(
std::forward<derived_type const &>(self),
std::forward<X_lambda>(p_lambda));
}

template<
typename T_value,
typename T_derived>
template<
typename X_lambda>
auto base_stream<T_value, T_derived>
::map(X_lambda&& p_lambda) &
{
using lambda_type = X_lambda;
using map_type = __stream::map_impl<derived_type, lambda_type>;

auto& self = static_cast<derived_type &>(*this);

return map_type(
std::forward<derived_type &>(self),
std::forward<X_lambda>(p_lambda));
}

template<
typename T_value,
typename T_derived>
template<
typename X_lambda>
auto base_stream<T_value, T_derived>
::map(X_lambda&& p_lambda) &&
{
using lambda_type = X_lambda;
using map_type = __stream::map_impl<derived_type, lambda_type>;

auto& self = static_cast<derived_type &>(*this);

return map_type(
std::forward<derived_type &&>(self),
std::forward<X_lambda>(p_lambda));
}

/* base_stream::flatten */

template<
typename T_value,
typename T_derived>
auto base_stream<T_value, T_derived>
::flatten() const &
{
using flatten_type = __stream::flatten_impl<derived_type>;

auto& self = static_cast<derived_type const &>(*this);

return flatten_type(
std::forward<derived_type const &>(self));
}

template<
typename T_value,
typename T_derived>
auto base_stream<T_value, T_derived>
::flatten() &
{
using flatten_type = __stream::flatten_impl<derived_type>;

auto& self = static_cast<derived_type &>(*this);

return flatten_type(
std::forward<derived_type &>(self));
}

template<
typename T_value,
typename T_derived>
auto base_stream<T_value, T_derived>
::flatten() &&
{
using flatten_type = __stream::flatten_impl<derived_type>;

auto& self = static_cast<derived_type &>(*this);

return flatten_type(
std::forward<derived_type &&>(self));
}

/* base_stream::timeout */

#ifdef asyncpp_timing


+ 47
- 0
include/asyncpp/core/stream/flatten.h Целия файл

@@ -0,0 +1,47 @@
#pragma once

#include <memory>

#include <asyncpp/core/stream.pre.h>

namespace asyncpp {
namespace __stream {

template<
typename T_stream>
struct flatten_impl final :
public base_stream<
typename T_stream::value_type::value_type,
flatten_impl<T_stream>
>
{
public:
using stream_type = T_stream;
using inner_stream_type = typename stream_type::value_type;
using inner_stream_ptr_u = std::unique_ptr<inner_stream_type>;
using value_type = typename inner_stream_type::value_type;
using this_type = flatten_impl<stream_type>;
using base_stream_type = base_stream<value_type, this_type>;
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();
};

} }

+ 49
- 0
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<T_stream>::flatten_impl(
X_stream&& p_stream)
: _stream (std::forward<X_stream>(p_stream))
, _inner ()
{ }

template<
typename T_stream>
typename flatten_impl<T_stream>::result_type
flatten_impl<T_stream>
::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<inner_stream_type>(std::move(*r));
}
}

} }

+ 3
- 3
include/asyncpp/core/stream/for_each.h Целия файл

@@ -22,9 +22,9 @@ namespace __stream {
using base_future_type = base_future<value_type, this_type>;
using result_type = typename base_future_type::result_type;

public:
stream_type stream;
lambda_type lambda;
private:
stream_type _stream;
lambda_type _lambda;

public:
/**


+ 4
- 4
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<X_stream>(p_stream))
, lambda(std::forward<X_lambda>(p_lambda))
: _stream(std::forward<X_stream>(p_stream))
, _lambda(std::forward<X_lambda>(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);
}
}



+ 48
- 0
include/asyncpp/core/stream/map.h Целия файл

@@ -0,0 +1,48 @@
#pragma once

#include <asyncpp/core/stream.pre.h>

namespace asyncpp {
namespace __stream {

template<
typename T_stream,
typename T_lambda>
struct map_impl final :
public base_stream<
decltype(std::declval<T_lambda>()(std::declval<typename T_stream::value_type>())),
map_impl<T_stream, T_lambda>
>
{
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<lambda_type>()(std::declval<inner_value_type>()));
using this_type = map_impl<stream_type, lambda_type>;
using base_stream_type = base_stream<value_type, this_type>;
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();
};

} }

+ 40
- 0
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<T_stream, T_lambda>::map_impl(
X_stream&& p_stream,
X_lambda&& p_lambda)
: _stream(std::forward<X_stream>(p_stream))
, _lambda(std::forward<X_lambda>(p_lambda))
{ }

template<
typename T_stream,
typename T_lambda>
typename map_impl<T_stream, T_lambda>::result_type
map_impl<T_stream, T_lambda>
::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();
}

} }

+ 5
- 0
include/asyncpp/fs.h Целия файл

@@ -0,0 +1,5 @@
#pragma once

#include "fs/directory.h"

#include "fs/directory.inl"

+ 43
- 0
include/asyncpp/fs/directory.h Целия файл

@@ -0,0 +1,43 @@
#pragma once

#include <string>

#include <cppfs/path.h>

#include <asyncpp/core/stream.pre.h>
#include <asyncpp/core/future/lazy.h>

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

} }

+ 167
- 0
include/asyncpp/fs/directory.inl Целия файл

@@ -0,0 +1,167 @@
#pragma once

#include <vector>

#include <cppfs/directory.h>

#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<value_type, this_type>;
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<value_type, this_type>;
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>;

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

} }

+ 2
- 0
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
$<INSTALL_INTERFACE:${ASYNCPP_INSTALL_DIR_INCLUDE}> )
Target_Link_Libraries ( asyncpp
INTERFACE
cppfs::cppfs
cppcore::cppcore )

# Install #########################################################################################


+ 17
- 1
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);
}

+ 69
- 0
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());
}

+ 210
- 0
test/asyncpp/fs/directory_tests.cpp Целия файл

@@ -0,0 +1,210 @@
#include <gtest/gtest.h>

#include <asyncpp.h>
#include <asyncpp/fs.h>

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<std::string>();
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<std::string>({
"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<cppfs::directory::entry>();
while ((r = s.poll()).is_ready())
entries.emplace_back(*r);

ASSERT_TRUE(r.is_done());

std::sort(entries.begin(), entries.end());

std::vector<std::string> paths;
paths.reserve(entries.size());
std::transform(
entries.begin(),
entries.end(),
std::back_inserter(paths),
[](auto& e) {
auto s = std::to_string(static_cast<int>(e.type)) + e.path.str();
return s;
});

EXPECT_EQ(paths, std::vector<std::string>({
"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());
}

Зареждане…
Отказ
Запис