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. |
|||
# SPDX-License-Identifier: Apache-2.0 |
|||
|
|||
add_subdirectory(clock) |
|||
add_subdirectory(libp2p) |
|||
|
|||
add_library(testutil INTERFACE) |
|||
target_link_libraries(testutil INTERFACE |
|||
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