diff --git a/googletest/include/gtest/gtest-param-test.h b/googletest/include/gtest/gtest-param-test.h index f5caed68c..5565f3468 100644 --- a/googletest/include/gtest/gtest-param-test.h +++ b/googletest/include/gtest/gtest-param-test.h @@ -360,6 +360,47 @@ internal::ParamGenerator> Values(Ts... vs) { // inline internal::ParamGenerator Bool() { return Values(false, true); } +// CombineAs() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements converted to +// the required type. +// +// Synopsis: +// CombineAs(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// Myclass where elements from sequences produced by gen1, gen2, ..., genN +// was provided to the MyClass constructor parameters. +// +// Example: +// +// This will instantiate tests in test suite AnimalTest each one with +// the parameter values Animal("cat", BLACK), Animal("cat", WHITE), +// Animal("dog", BLACK), and Animal("dog", WHITE): +// enum Color { BLACK, GRAY, WHITE }; +// +// struct Animal { +// std::string name; +// Color color; +// }; +// +// class AnimalTest +// : public testing::TestWithParam {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, +// CombineAs(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +template +internal::ParamGenerator CombineAs( + internal::ParamGenerator&&... generators) { + return internal::ParamGenerator( + new internal::CartesianProductGenerator( + std::forward(generators)...)); +} + // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // @@ -407,9 +448,8 @@ inline internal::ParamGenerator Bool() { return Values(false, true); } template internal::ParamGenerator> Combine( internal::ParamGenerator&&... generators) { - return internal::ParamGenerator>( - new internal::CartesianProductGenerator, T...>( - std::forward(generators)...)); + return CombineAs, T...>( + std::forward(generators)...); } // ConvertGenerator() wraps a parameter generator in order to cast each produced diff --git a/googletest/include/gtest/internal/gtest-param-util.h b/googletest/include/gtest/internal/gtest-param-util.h index b2bdf16de..8c7c34fb7 100644 --- a/googletest/include/gtest/internal/gtest-param-util.h +++ b/googletest/include/gtest/internal/gtest-param-util.h @@ -902,7 +902,8 @@ class CartesianProductGenerator : public ParamGeneratorInterface { void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = std::make_shared(*std::get(current_)...); + current_value_ = + std::make_shared(ParamType{*std::get(current_)...}); } bool AtEnd() const { bool at_end = false; diff --git a/googletest/test/googletest-param-test-test.cc b/googletest/test/googletest-param-test-test.cc index 10d429c9a..1b46fa28a 100644 --- a/googletest/test/googletest-param-test-test.cc +++ b/googletest/test/googletest-param-test-test.cc @@ -588,6 +588,70 @@ TEST(ConvertTest, NonDefaultConstructAssign) { EXPECT_TRUE(it == gen.end()); } +TEST(CombineAsTest, DefaultConstructible) { + struct DefaultConstructible { + int x; + std::string s; + + bool operator==(const DefaultConstructible& other) const { + return x == other.x && s == other.s; + } + }; + + static_assert(std::is_default_constructible_v); + ParamGenerator gen = + testing::CombineAs(Values(0, 1), Values("A", "B")); + + DefaultConstructible expected_values[] = { + {0, "A"}, {0, "B"}, {1, "A"}, {1, "B"}}; + VerifyGenerator(gen, expected_values); +} + +TEST(CombineAsTest, NonDefaultConstructible) { + class NonDefaultConstructible { + public: + NonDefaultConstructible(const int i_arg, std::string s_arg) + : i_(i_arg), s_(std::move(s_arg)) {} + + bool operator==(const NonDefaultConstructible& other) const { + return i_ == other.i_ && s_ == other.s_; + } + + private: + int i_; + std::string s_; + }; + + static_assert(!std::is_default_constructible_v); + ParamGenerator gen = + testing::CombineAs(Values(0, 1), + Values("A", "B")); + + NonDefaultConstructible expected_values[] = { + {0, "A"}, {0, "B"}, {1, "A"}, {1, "B"}}; + VerifyGenerator(gen, expected_values); +} + +TEST(CombineAsTest, CopyConstructible) { + struct CopyConstructible { + CopyConstructible(const CopyConstructible& other) = default; + + bool operator==(const CopyConstructible& other) const { + return x == other.x && s == other.s; + } + + int x; + std::string s; + }; + + static_assert(std::is_copy_constructible_v); + ParamGenerator gen = testing::CombineAs( + Values(CopyConstructible{0, "A"}, CopyConstructible{1, "B"})); + CopyConstructible expected_values[] = {CopyConstructible{0, "A"}, + CopyConstructible{1, "B"}}; + VerifyGenerator(gen, expected_values); +} + TEST(ConvertTest, WithConverterLambdaAndDeducedType) { const ParamGenerator> gen = ConvertGenerator(Values("0", std::string("1")), [](const std::string& s) {