Skip to content

Commit

Permalink
Simplify suite_builder and test_caller
Browse files Browse the repository at this point in the history
This lets us remove some repeated tuple-expansion.
  • Loading branch information
jimporter committed Aug 11, 2024
1 parent 8144723 commit d8f9e15
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 103 deletions.
52 changes: 20 additions & 32 deletions include/mettle/suite/detail/test_caller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace mettle::detail {
struct test_caller_base {
using function_type = std::function<void(Args&...)>;

void call_test(Args &...args) {
void operator ()(Args &...args) {
if(setup)
setup(args...);

Expand All @@ -48,49 +48,37 @@ namespace mettle::detail {
function_type setup, teardown, test;
};

template<typename Factory, typename Parent, typename InChild,
typename OutChild>
class test_caller_impl;
template<typename ...Parent>
struct test_caller : test_caller_base<Parent &...> {
private:
using base = test_caller_base<Parent &...>;
public:
template<typename Factory, typename ...T>
test_caller(const Factory &, T &&...t)
: base{std::forward<T>(t)...} {}
};

template<typename Factory, typename ...Parent, typename InChild,
typename OutChild>
class test_caller_impl<Factory, std::tuple<Parent...>, InChild, OutChild>
: private test_caller_base<Parent &..., OutChild &> {
template<typename Factory, typename Child, typename ...Parent>
struct fixture_test_caller : test_caller_base<
Parent &..., transform_fixture_t<Factory, Child> &
> {
private:
using base = test_caller_base<Parent &..., OutChild &>;
using base = test_caller_base<
Parent &..., transform_fixture_t<Factory, Child> &
>;
public:
template<typename ...T>
test_caller_impl(Factory f, T &&...t)
fixture_test_caller(Factory f, T &&...t)
: base{std::forward<T>(t)...}, factory(std::move(f)) {}

inline void operator ()(Parent &...args) {
auto &&child = factory.template make<InChild>();
base::call_test(args..., child);
auto &&child = factory.template make<Child>();
base::operator ()(args..., child);
}

Factory factory;
};

template<typename Factory, typename ...Parent, typename InChild>
class test_caller_impl<Factory, std::tuple<Parent...>, InChild, void>
: private test_caller_base<Parent &...> {
private:
using base = test_caller_base<Parent &...>;
public:
template<typename ...T>
test_caller_impl(const Factory &, T &&...t)
: base{std::forward<T>(t)...} {}
public:
inline void operator ()(Parent &...args) {
base::call_test(args...);
}
};

template<typename Factory, typename Parent, typename Child>
using test_caller = test_caller_impl<
Factory, Parent, Child, transform_fixture_t<Factory, Child>
>;

} // namespace mettle::detail

#endif
85 changes: 41 additions & 44 deletions include/mettle/suite/make_suite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,6 @@ namespace mettle {
return s + " (" + type_name<T>() + ")";
}

template<typename Tuple>
struct to_func_impl;

template<typename ...T>
struct to_func_impl<std::tuple<T...>> {
using type = void(T&...);
};

template<typename T>
using to_func = typename to_func_impl<T>::type;


template<typename Exception>
struct wrap_test {
using compiled_suite_type = runnable_suite;
Expand Down Expand Up @@ -72,9 +60,7 @@ namespace mettle {

template<typename Wrap, typename Builder, typename = std::void_t<>>
struct wrapped_suite {
using type = compiled_suite<to_func<
typename Builder::parent_fixture_type
>>;
using type = compiled_suite<typename Builder::parent_fixture_signature>;
};

template<typename Wrap, typename Builder>
Expand Down Expand Up @@ -172,7 +158,7 @@ namespace mettle {


template<typename ParentFixture, typename ...Fixture, typename ...Args>
inline compiled_suite<detail::to_func<ParentFixture>>
inline auto
make_subsuite(const std::string &name, const attributes &attrs,
Args &&...args) {
return detail::do_build<ParentFixture, Fixture...>(
Expand All @@ -181,16 +167,15 @@ namespace mettle {
}

template<typename ParentFixture, typename ...Fixture, typename ...Args>
inline compiled_suite<detail::to_func<ParentFixture>>
inline auto
make_subsuite(const std::string &name, Args &&...args) {
return detail::do_build<ParentFixture, Fixture...>(
name, {}, std::forward<Args>(args)..., detail::identity{}
);
}

template<typename ParentFixture, typename ...Fixture, typename ...Args>
inline std::array<compiled_suite<detail::to_func<ParentFixture>>,
std::max(sizeof...(Fixture), std::size_t(1))>
inline auto
make_subsuites(const std::string &name, const attributes &attrs,
Args &&...args) {
return detail::do_builds<ParentFixture, Fixture...>(
Expand All @@ -199,8 +184,7 @@ namespace mettle {
}

template<typename ParentFixture, typename ...Fixture, typename ...Args>
inline std::array<compiled_suite<detail::to_func<ParentFixture>>,
std::max(sizeof...(Fixture), std::size_t(1))>
inline auto
make_subsuites(const std::string &name, Args &&...args) {
return detail::do_builds<ParentFixture, Fixture...>(
name, {}, std::forward<Args>(args)..., detail::identity{}
Expand Down Expand Up @@ -308,39 +292,52 @@ namespace mettle {
std::vector<compiled_suite<void(T&...)>> subsuites_;
};

template<typename Factory, typename Parent, typename InChild>
struct suite_builder_base_type;
template<typename Factory, typename ...ParentFixture,
typename Fixture /* = detail::no_fixture_t*/>
requires(std::same_as<detail::transform_fixture_t<Factory, Fixture>, void>)
class suite_builder<Factory, std::tuple<ParentFixture...>, Fixture>
: public suite_builder_base<ParentFixture...> {
using base = suite_builder_base<ParentFixture...>;
public:
using factory_type = Factory;
using parent_fixture_type = std::tuple<ParentFixture...>;
using parent_fixture_signature = void(ParentFixture&...);
using fixture_type = Fixture;

template<typename Factory, typename ...Parent, typename InChild>
struct suite_builder_base_type<Factory, std::tuple<Parent...>, InChild> {
using out_child_type = detail::transform_fixture_t<Factory, InChild>;
using type = std::conditional_t<
std::is_same_v<out_child_type, void>,
suite_builder_base<Parent...>,
suite_builder_base<Parent..., out_child_type>
>;
};
suite_builder(const std::string &name, const attributes &attrs,
Factory factory)
: base(name, attrs), factory_(factory) {}
private:
using test_caller = detail::test_caller<ParentFixture...>;

template<typename Builder, typename Wrap>
friend typename detail::wrapped_suite<Wrap, Builder>::type
detail::finalize(Builder &, const Wrap &);

template<typename Factory, typename Parent, typename InChild>
using suite_builder_base_t = typename suite_builder_base_type<
Factory, Parent, InChild
>::type;
factory_type factory_;
};

template<typename Factory, typename ParentFixture,
typename Fixture /* = detail::no_fixture_t */>
class suite_builder
: public suite_builder_base_t<Factory, ParentFixture, Fixture> {
using base = suite_builder_base_t<Factory, ParentFixture, Fixture>;
public:
template<typename Factory, typename ...ParentFixture,
typename Fixture /* = detail::no_fixture_t*/>
class suite_builder<Factory, std::tuple<ParentFixture...>, Fixture>
: public suite_builder_base<ParentFixture...,
detail::transform_fixture_t<Factory, Fixture>> {
using base = suite_builder_base<
ParentFixture..., detail::transform_fixture_t<Factory, Fixture>
>;
public:
using factory_type = Factory;
using parent_fixture_type = ParentFixture;
using parent_fixture_type = std::tuple<ParentFixture...>;
using parent_fixture_signature = void(ParentFixture&...);
using fixture_type = Fixture;

suite_builder(const std::string &name, const attributes &attrs,
Factory factory)
: base(name, attrs), factory_(factory) {}
private:
using test_caller = detail::test_caller<Factory, ParentFixture, Fixture>;
using test_caller = detail::fixture_test_caller<
Factory, Fixture, ParentFixture...
>;

template<typename Builder, typename Wrap>
friend typename detail::wrapped_suite<Wrap, Builder>::type
Expand Down
51 changes: 24 additions & 27 deletions test/suite/test_test_caller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,52 @@ using namespace mettle;

#include "run_counter.hpp"

template<typename Tuple>
struct run_counter_from_tuple_t;

template<typename ...T>
struct run_counter_from_tuple_t<std::tuple<T...>> {
using type = run_counter<T &...>;
template<template<typename ...> typename T, typename Tuple,
template<typename ...> typename Transform>
struct apply_tuple_t;

template<template<typename ...> typename T, typename ...Args,
template<typename ...> typename Transform>
struct apply_tuple_t<T, std::tuple<Args...>, Transform> {
using type = T<Transform<Args>...>;
};

template<template<typename ...> typename T, typename Tuple,
template<typename ...> typename Transform = std::type_identity_t>
using apply_tuple = typename apply_tuple_t<T, Tuple, Transform>::type;

template<typename Tuple>
using run_counter_from_tuple = typename run_counter_from_tuple_t<Tuple>::type;
using run_counter_from_tuple = apply_tuple<
run_counter, Tuple, std::add_lvalue_reference_t
>;


using namespace mettle::detail;

suite<std::tuple<>, std::tuple<int, int>>
test_test_caller("test_caller", [](auto &_) {
using Fixture = fixture_type_t<decltype(_)>;

_.test("test with no fixture", [](auto &tup) {
_.test("no fixture", [](auto &tup) {
run_counter_from_tuple<Fixture> setup, teardown, test;
test_caller<auto_factory_t, Fixture, no_fixture_t> t(
apply_tuple<test_caller, Fixture> caller(
auto_factory, setup, teardown, test
);
std::apply(t, tup);
std::apply(caller, tup);

expect("setup run count", setup.runs(), equal_to(1));
expect("test run count", test.runs(), equal_to(1));
expect("teardown run count", teardown.runs(), equal_to(1));
});

_.test("test with auto fixture", [](auto &tup) {
_.test("fixture", [](auto &tup) {
run_counter_from_tuple<decltype(
std::tuple_cat(tup, std::tuple<int>())
)> setup, teardown, test;
test_caller<auto_factory_t, Fixture, int> t(
auto_factory, setup, teardown, test
);
std::apply(t, tup);

expect("setup run count", setup.runs(), equal_to(1));
expect("test run count", test.runs(), equal_to(1));
expect("teardown run count", teardown.runs(), equal_to(1));
});

_.test("test with type-only fixture", [](auto &tup) {
run_counter_from_tuple<Fixture> setup, teardown, test;
test_caller<type_only_factory_t, Fixture, int> t(
type_only, setup, teardown, test
);
std::apply(t, tup);
apply_tuple<fixture_test_caller, decltype(
std::tuple_cat(std::tuple<auto_factory_t, int>(), tup)
)> caller(auto_factory, setup, teardown, test);
std::apply(caller, tup);

expect("setup run count", setup.runs(), equal_to(1));
expect("test run count", test.runs(), equal_to(1));
Expand Down

0 comments on commit d8f9e15

Please sign in to comment.