mirror of https://github.com/libp2p/cpp-libp2p.git
Yura Zarudniy
5 years ago
33 changed files with 503 additions and 114 deletions
@ -0,0 +1,102 @@ |
|||||
|
/**
|
||||
|
* Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
*/ |
||||
|
|
||||
|
#ifndef LIBP2P_VISITOR_HPP |
||||
|
#define LIBP2P_VISITOR_HPP |
||||
|
|
||||
|
#include <type_traits> // for std::decay |
||||
|
#include <utility> // for std::forward |
||||
|
|
||||
|
#include <boost/variant/apply_visitor.hpp> // for boost::apply_visitor |
||||
|
|
||||
|
namespace libp2p { |
||||
|
|
||||
|
template <typename... Lambdas> |
||||
|
struct lambda_visitor; |
||||
|
|
||||
|
template <typename Lambda, typename... Lambdas> |
||||
|
struct lambda_visitor<Lambda, Lambdas...> |
||||
|
: public Lambda, public lambda_visitor<Lambdas...> { |
||||
|
using Lambda::operator(); |
||||
|
using lambda_visitor<Lambdas...>::operator(); |
||||
|
|
||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
|
lambda_visitor(Lambda lambda, Lambdas... lambdas) |
||||
|
: Lambda(lambda), lambda_visitor<Lambdas...>(lambdas...) {} |
||||
|
}; |
||||
|
|
||||
|
template <typename Lambda> |
||||
|
struct lambda_visitor<Lambda> : public Lambda { |
||||
|
using Lambda::operator(); |
||||
|
|
||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
|
lambda_visitor(Lambda lambda) : Lambda(lambda) {} |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Convenient in-place compile-time visitor creation, from a set of |
||||
|
* lambdas |
||||
|
* |
||||
|
* @code |
||||
|
* make_visitor([](int a){ return 1; }, |
||||
|
* [](std::string b) { return 2; }); |
||||
|
* @nocode |
||||
|
* |
||||
|
* is essentially the same as |
||||
|
* |
||||
|
* @code |
||||
|
* struct visitor : public boost::static_visitor<int> { |
||||
|
* int operator()(int a) { return 1; } |
||||
|
* int operator()(std::string b) { return 2; } |
||||
|
* } |
||||
|
* @nocode |
||||
|
* |
||||
|
* @param lambdas |
||||
|
* @return visitor |
||||
|
*/ |
||||
|
template <class... Fs> |
||||
|
constexpr auto make_visitor(Fs &&... fs) { |
||||
|
using visitor_type = lambda_visitor<std::decay_t<Fs>...>; |
||||
|
return visitor_type(std::forward<Fs>(fs)...); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* @brief Inplace visitor for boost::variant. |
||||
|
* @code |
||||
|
* boost::variant<int, std::string> value = "1234"; |
||||
|
* ... |
||||
|
* visit_in_place(value, |
||||
|
* [](int v) { std::cout << "(int)" << v; }, |
||||
|
* [](std::string v) { std::cout << "(string)" << v;} |
||||
|
* ); |
||||
|
* @nocode |
||||
|
* |
||||
|
* @param variant |
||||
|
* @param lambdas |
||||
|
* @param lambdas |
||||
|
*/ |
||||
|
template <typename TVariant, typename... TVisitors> |
||||
|
constexpr decltype(auto) visit_in_place(TVariant &&variant, |
||||
|
TVisitors &&... visitors) { |
||||
|
return boost::apply_visitor( |
||||
|
make_visitor(std::forward<TVisitors>(visitors)...), |
||||
|
std::forward<TVariant>(variant)); |
||||
|
} |
||||
|
|
||||
|
/// apply Matcher to optional T
|
||||
|
template <typename T, typename Matcher> |
||||
|
constexpr decltype(auto) match(T &&t, Matcher &&m) { |
||||
|
return std::forward<T>(t) ? std::forward<Matcher>(m)(*std::forward<T>(t)) |
||||
|
: std::forward<Matcher>(m)(); |
||||
|
} |
||||
|
|
||||
|
/// construct visitor from Fs and apply it to optional T
|
||||
|
template <typename T, typename... Fs> |
||||
|
constexpr decltype(auto) match_in_place(T &&t, Fs &&... fs) { |
||||
|
return match(std::forward<T>(t), make_visitor(std::forward<Fs>(fs)...)); |
||||
|
} |
||||
|
} // namespace kagome
|
||||
|
|
||||
|
#endif // LIBP2P_VISITOR_HPP
|
@ -0,0 +1,11 @@ |
|||||
|
# |
||||
|
# Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
# SPDX-License-Identifier: Apache-2.0 |
||||
|
# |
||||
|
|
||||
|
addtest(outcome_test outcome_test.cpp) |
||||
|
target_link_libraries(outcome_test |
||||
|
outcome |
||||
|
) |
||||
|
|
||||
|
addtest(di_test di_test.cpp) |
@ -0,0 +1,63 @@ |
|||||
|
/**
|
||||
|
* Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
*/ |
||||
|
|
||||
|
#include <gtest/gtest.h> |
||||
|
#include <boost/di.hpp> |
||||
|
|
||||
|
class ctor { |
||||
|
public: |
||||
|
explicit ctor(int i) : i(i) {} |
||||
|
int i; |
||||
|
}; |
||||
|
|
||||
|
struct aggregate { |
||||
|
double d; |
||||
|
}; |
||||
|
|
||||
|
class example { |
||||
|
public: |
||||
|
virtual ~example() = default; |
||||
|
|
||||
|
example(aggregate a, const ctor &c) { |
||||
|
EXPECT_EQ(87.0, a.d); |
||||
|
EXPECT_EQ(42, c.i); |
||||
|
}; |
||||
|
|
||||
|
virtual void func() {} |
||||
|
}; |
||||
|
|
||||
|
struct Derived : public example { |
||||
|
~Derived() override = default; |
||||
|
|
||||
|
void func() override {} |
||||
|
}; |
||||
|
|
||||
|
template <typename... T> |
||||
|
auto useBind(){ |
||||
|
return boost::di::bind<example*[]>.template to<T...>(); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* @brief If test compiles, then DI works. |
||||
|
*/ |
||||
|
TEST(Boost, DI) { |
||||
|
using namespace boost; |
||||
|
|
||||
|
// clang-format off
|
||||
|
const auto injector = di::make_injector( |
||||
|
di::bind<int>.to(42)[boost::di::override], |
||||
|
di::bind<double>.to(87.0), |
||||
|
useBind<Derived>() |
||||
|
); |
||||
|
// clang-format on
|
||||
|
|
||||
|
auto a = injector.create<example>(); |
||||
|
auto b = injector.create<std::shared_ptr<example>>(); |
||||
|
auto c = injector.create<std::unique_ptr<example>>(); |
||||
|
|
||||
|
(void)a; |
||||
|
(void)b; |
||||
|
(void)c; |
||||
|
} |
@ -0,0 +1,120 @@ |
|||||
|
/**
|
||||
|
* Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
*/ |
||||
|
|
||||
|
#include <gtest/gtest.h> |
||||
|
#include <outcome/outcome.hpp> |
||||
|
#include <string> |
||||
|
|
||||
|
using std::string_literals::operator""s; |
||||
|
|
||||
|
#define ILLEGAL_CHAR_MSG "illegal char"s |
||||
|
#define DIV_0_MSG "division by 0"s |
||||
|
|
||||
|
enum class ConversionErrc { |
||||
|
SUCCESS = 0, // 0 should not represent an error
|
||||
|
EMPTY_STRING = 1, // (for rationale, see tutorial on error codes)
|
||||
|
ILLEGAL_CHAR = 2, |
||||
|
TOO_LONG = 3, |
||||
|
}; |
||||
|
|
||||
|
namespace sooper::loong::ns { |
||||
|
enum class DivisionErrc { |
||||
|
DIVISION_BY_ZERO = 1, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
OUTCOME_HPP_DECLARE_ERROR(ConversionErrc) |
||||
|
OUTCOME_CPP_DEFINE_CATEGORY(ConversionErrc, e) { |
||||
|
switch (e) { |
||||
|
case ConversionErrc::SUCCESS: |
||||
|
return "success"; |
||||
|
case ConversionErrc::EMPTY_STRING: |
||||
|
return "empty string"; |
||||
|
case ConversionErrc::ILLEGAL_CHAR: |
||||
|
return ILLEGAL_CHAR_MSG; |
||||
|
case ConversionErrc::TOO_LONG: |
||||
|
return "too long"; |
||||
|
default: |
||||
|
return "unknown"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
OUTCOME_HPP_DECLARE_ERROR(sooper::loong::ns, DivisionErrc) |
||||
|
OUTCOME_CPP_DEFINE_CATEGORY(sooper::loong::ns, DivisionErrc, e) { |
||||
|
using sooper::loong::ns::DivisionErrc; |
||||
|
switch (e) { |
||||
|
case DivisionErrc::DIVISION_BY_ZERO: |
||||
|
return "division by 0"; |
||||
|
default: |
||||
|
return "unknown"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
outcome::result<int> convert(const std::string &str) { |
||||
|
if (str.empty()) |
||||
|
return ConversionErrc::EMPTY_STRING; |
||||
|
|
||||
|
if (!std::all_of(str.begin(), str.end(), ::isdigit)) |
||||
|
return ConversionErrc::ILLEGAL_CHAR; |
||||
|
|
||||
|
if (str.length() > 9) |
||||
|
return ConversionErrc::TOO_LONG; |
||||
|
|
||||
|
return atoi(str.c_str()); |
||||
|
} |
||||
|
|
||||
|
outcome::result<int> divide(int a, int b) { |
||||
|
using sooper::loong::ns::DivisionErrc; |
||||
|
if (b == 0) |
||||
|
return DivisionErrc::DIVISION_BY_ZERO; |
||||
|
|
||||
|
return a / b; |
||||
|
} |
||||
|
|
||||
|
outcome::result<int> convert_and_divide(const std::string &a, |
||||
|
const std::string &b) { |
||||
|
OUTCOME_TRY(valA, convert(a)); |
||||
|
OUTCOME_TRY(valB, convert(b)); |
||||
|
OUTCOME_TRY(valDiv, divide(valA, valB)); |
||||
|
return valDiv; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* @given valid arguments for convert_and_divide |
||||
|
* @when execute method which returns result |
||||
|
* @then returns value |
||||
|
*/ |
||||
|
TEST(Outcome, CorrectCase) { |
||||
|
auto r = convert_and_divide("500", "2"); |
||||
|
ASSERT_TRUE(r); |
||||
|
auto &&val = r.value(); |
||||
|
ASSERT_EQ(val, 250); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* @given arguments to cause conversion error for convert_and_divide |
||||
|
* @when execute method which returns result |
||||
|
* @then returns error |
||||
|
*/ |
||||
|
TEST(Outcome, ConversionError) { |
||||
|
auto r = convert_and_divide("500", "a"); |
||||
|
ASSERT_FALSE(r); |
||||
|
auto &&err = r.error(); |
||||
|
ASSERT_EQ(err.message(), ILLEGAL_CHAR_MSG); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* @given arguments to cause division error for convert_and_divide |
||||
|
* @when execute method which returns result |
||||
|
* @then returns error |
||||
|
*/ |
||||
|
TEST(Outcome, DivisionError) { |
||||
|
auto r = convert_and_divide("500", "0"); |
||||
|
ASSERT_FALSE(r); |
||||
|
auto &&err = r.error(); |
||||
|
ASSERT_EQ(err.message(), DIV_0_MSG); // name of the enum
|
||||
|
using sooper::loong::ns::DivisionErrc; |
||||
|
ASSERT_EQ(err.category().name(), typeid(DivisionErrc).name()); |
||||
|
} |
@ -1,9 +1,11 @@ |
|||||
# Copyright Soramitsu Co., Ltd. All Rights Reserved. |
# Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
# SPDX-License-Identifier: Apache-2.0 |
# SPDX-License-Identifier: Apache-2.0 |
||||
|
|
||||
|
add_subdirectory(clock) |
||||
add_subdirectory(libp2p) |
add_subdirectory(libp2p) |
||||
|
|
||||
add_library(testutil INTERFACE) |
add_library(testutil INTERFACE) |
||||
target_link_libraries(testutil INTERFACE |
target_link_libraries(testutil INTERFACE |
||||
testutil_peer |
testutil_peer |
||||
|
clock |
||||
) |
) |
||||
|
@ -0,0 +1,8 @@ |
|||||
|
# |
||||
|
# Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
# SPDX-License-Identifier: Apache-2.0 |
||||
|
# |
||||
|
|
||||
|
add_library(clock |
||||
|
impl/clock_impl.cpp |
||||
|
) |
@ -0,0 +1,51 @@ |
|||||
|
/**
|
||||
|
* Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
*/ |
||||
|
|
||||
|
#ifndef LIBP2P_CLOCK_HPP |
||||
|
#define LIBP2P_CLOCK_HPP |
||||
|
|
||||
|
#include <chrono> |
||||
|
|
||||
|
namespace libp2p::clock { |
||||
|
|
||||
|
/**
|
||||
|
* An interface for a clock |
||||
|
* @tparam clock type is an underlying clock type, such as std::steady_clock |
||||
|
*/ |
||||
|
template <typename ClockType> |
||||
|
class Clock { |
||||
|
public: |
||||
|
/**
|
||||
|
* Difference between two time points |
||||
|
*/ |
||||
|
using Duration = typename ClockType::duration; |
||||
|
/**
|
||||
|
* A moment in time, stored in milliseconds since Unix epoch start |
||||
|
*/ |
||||
|
using TimePoint = typename ClockType::time_point; |
||||
|
|
||||
|
virtual ~Clock() = default; |
||||
|
|
||||
|
/**
|
||||
|
* @return a time point representing the current time |
||||
|
*/ |
||||
|
virtual TimePoint now() const = 0; |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* SteadyClock alias over Clock. Should be used when we need to measure |
||||
|
* interval between two moments in time |
||||
|
*/ |
||||
|
using SteadyClock = Clock<std::chrono::steady_clock>; |
||||
|
|
||||
|
/**
|
||||
|
* SystemClock alias over Clock. Should be used when we need to watch current |
||||
|
* time |
||||
|
*/ |
||||
|
using SystemClock = Clock<std::chrono::system_clock>; |
||||
|
|
||||
|
} // namespace libp2p::clock
|
||||
|
|
||||
|
#endif // LIBP2P_CLOCK_HPP
|
@ -0,0 +1,18 @@ |
|||||
|
/**
|
||||
|
* Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
*/ |
||||
|
|
||||
|
#include "testutil/clock/impl/clock_impl.hpp" |
||||
|
|
||||
|
namespace libp2p::clock { |
||||
|
|
||||
|
template <typename ClockType> |
||||
|
typename Clock<ClockType>::TimePoint ClockImpl<ClockType>::now() const { |
||||
|
return ClockType::now(); |
||||
|
} |
||||
|
|
||||
|
template class ClockImpl<std::chrono::steady_clock>; |
||||
|
template class ClockImpl<std::chrono::system_clock>; |
||||
|
|
||||
|
} // namespace libp2p::clock
|
@ -0,0 +1,25 @@ |
|||||
|
/**
|
||||
|
* Copyright Soramitsu Co., Ltd. All Rights Reserved. |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
*/ |
||||
|
|
||||
|
#ifndef LIBP2P_CLOCK_IMPL_CLOCK_IMPL_HPP |
||||
|
#define LIBP2P_CLOCK_IMPL_CLOCK_IMPL_HPP |
||||
|
|
||||
|
#include "testutil/clock/clock.hpp" |
||||
|
|
||||
|
namespace libp2p::clock { |
||||
|
|
||||
|
template <typename ClockType> |
||||
|
class ClockImpl : public Clock<ClockType> { |
||||
|
public: |
||||
|
typename Clock<ClockType>::TimePoint now() const override; |
||||
|
}; |
||||
|
|
||||
|
// aliases for implementations
|
||||
|
using SteadyClockImpl = ClockImpl<std::chrono::steady_clock>; |
||||
|
using SystemClockImpl = ClockImpl<std::chrono::system_clock>; |
||||
|
|
||||
|
} // namespace libp2p::clock
|
||||
|
|
||||
|
#endif // LIBP2P_CLOCK_IMPL_CLOCK_IMPL_HPP
|
Loading…
Reference in new issue