Home > Enterprise >  how can I get generate implement type for gtest?
how can I get generate implement type for gtest?

Time:11-30

there is some enum class like

enum class first{
        a,
        b,
        ...
};

enum class second{
        c,
        d,
        ...
};

the class seems like

template<first N, second M> class A{
        public:
                A(){}
                A(int n) {
                        var = n;
                }
                int var;
};

I wanto use it in gtest which is

template<typename T> class TestA : public ::testing::Test {};


TYPED_TEST_CASE_P(TestA);

TYPED_TEST_P(TestA, SomeTest){
            TypeParam x(0);
            EXPECT_EQ(x.var,0);
}

REGISTER_TYPED_TEST_CASE_P(TestA, SomeTest);

typedef ::testing::Types<A<first::a, second::c>, A<first::b, second::d>...> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, TestA, MyTypes);

int main(int argc, char **argv) {
            ::testing::InitGoogleTest(&argc, argv);
            return RUN_ALL_TESTS();
}

how can i generate combinations of all possible template parameters so it easily add test case by increasing enum number maybe there is 3 or more param

::testing::Types<A<first::a, second::c>, A<first::a, second::c>, A<first::b, second::c>, A<first::b, second::c>>
::testing::Types<A<first::a, second::c, third::e>, A<first::a, second::c, third::f>...>

I try to contain them in template struct looks like this then I cam make impl just like

::testing::Combine(Base<first::a, first::b, ...>,Base<second::c, second::d, ...>;)

to generate

::testing::Types<A<first::a, second::c>, A<first::c, second::d>.....>

maybe there is 3 or more param

::testing::Types<A<000>, A<001>, A<010>, A<011>>.....

CodePudding user response:

Provided your enums all have 0 as start value and do not contain gaps in between any two values then you can generate via the following approach (for any number of arguments/enums); note that this goes via an intermediate step of std::tuples as for these there's std::tuple_cat available (instead of having to write an own, direct concatenation for testing::Types template):

template <size_t N, size_t ... NN>
class Generate<N, NN...>
{
    template <size_t ... NNN>
    friend class Generate;

    template <size_t S>
    class Concat
    {
        template <size_t ... SS>
        auto concat(A<SS...>)
        {
            return A<S, SS...>();
        }
    public:
        template <typename ... T>
        auto operator()(std::tuple<T...> const& t)
        {
            return std::apply
            (
                [this](auto ... t)
                {
                    return std::tuple(concat(t)...);
                },
                t
            );
        }
    };
    template <size_t ... S>
    static auto generate(std::index_sequence<S...>)
    {
        using Base = typename Generate<NN...>::internal;
        return std::tuple_cat(Concat<S>()(Base())...);
    }

    template <typename ... T>
    static auto translate(std::tuple<T...>)
    {
        return Types<T...>();
    }

    using internal = decltype(generate(std::make_index_sequence<N>()));

public:
    using type = decltype(translate(internal()));
};

The nested class allows to specify the single constants without having to specify the variadic types which would have been pretty cumbersome (if possible at all...).

Demonstration (with custom A and Types types) on godbolt.

CodePudding user response:

Here is my template tool, note this doesn't require use of integer sequence:

namespace detail {
template <auto... values>
struct value_list {
    template <auto newValue>
    using append = value_list<values..., newValue>;

    template <template <auto...> typename T>
    using apply_on = T<values...>;
};

template <typename... Ts>
struct concat_types_list;

template <template <typename...> typename Tem, typename... As>
struct concat_types_list<Tem<As...>> {
    using type = Tem<As...>;
};

template <template <typename...> typename Tem, typename... As, typename... Bs, typename... Remaning>
struct concat_types_list<Tem<As...>, Tem<Bs...>, Remaning...> {
    using type = typename concat_types_list<Tem<As..., Bs...>, Remaning...>::type;
};

template <typename... Ts>
using concat_types_list_t = typename concat_types_list<Ts...>::type;

template <typename... Ts>
struct value_generator {
    using type = value_generator;

    template <auto value>
    using for_each_append = value_generator<typename Ts::template append<value>...>;

    template <auto... Values>
    using mutiply = concat_types_list_t<for_each_append<Values>...>;

    template <template <typename...> typename Out, template <auto...> typename In>
    using compose = Out<typename Ts::template apply_on<In>...>;
};
}

using value_generator_t = detail::value_generator<detail::value_list<>>;

Use is quite nice:

using MyTypes = value_generator_t
    ::mutiply<first::a, first::b, first::x, first::y>
    ::mutiply<second::c, second::e, second::f>
    ::compose<::testing::Types, A>;

https://godbolt.org/z/8d9e4Trqb

  • Related