Skip to content

Commit dc9ed8e

Browse files
committed
Add CombineAs<R>() generator function
`CombineAs<R>()` allows to construct the required type directly from combined arguments. As it would be a composition of `ConvertGenerator()` and `Combine()`, but without `std::tuple` in between.
1 parent 15c8651 commit dc9ed8e

File tree

3 files changed

+109
-4
lines changed

3 files changed

+109
-4
lines changed

googletest/include/gtest/gtest-param-test.h

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,47 @@ internal::ParamGenerator<std::common_type_t<Ts...>> Values(Ts... vs) {
360360
//
361361
inline internal::ParamGenerator<bool> Bool() { return Values(false, true); }
362362

363+
// CombineAs() allows the user to combine two or more sequences to produce
364+
// values of a Cartesian product of those sequences' elements converted to
365+
// the required type.
366+
//
367+
// Synopsis:
368+
// CombineAs<MyClass>(gen1, gen2, ..., genN)
369+
// - returns a generator producing sequences with elements coming from
370+
// the Cartesian product of elements from the sequences generated by
371+
// gen1, gen2, ..., genN. The sequence elements will have a type of
372+
// Myclass where elements from sequences produced by gen1, gen2, ..., genN
373+
// was provided to the MyClass constructor parameters.
374+
//
375+
// Example:
376+
//
377+
// This will instantiate tests in test suite AnimalTest each one with
378+
// the parameter values Animal("cat", BLACK), Animal("cat", WHITE),
379+
// Animal("dog", BLACK), and Animal("dog", WHITE):
380+
// enum Color { BLACK, GRAY, WHITE };
381+
//
382+
// struct Animal {
383+
// std::string name;
384+
// Color color;
385+
// };
386+
//
387+
// class AnimalTest
388+
// : public testing::TestWithParam<Animal> {...};
389+
//
390+
// TEST_P(AnimalTest, AnimalLooksNice) {...}
391+
//
392+
// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest,
393+
// CombineAs<Animal>(Values("cat", "dog"),
394+
// Values(BLACK, WHITE)));
395+
//
396+
template <typename R, typename... T>
397+
internal::ParamGenerator<R> CombineAs(
398+
internal::ParamGenerator<T>&&... generators) {
399+
return internal::ParamGenerator<R>(
400+
new internal::CartesianProductGenerator<R, T...>(
401+
std::forward<decltype(generators)>(generators)...));
402+
}
403+
363404
// Combine() allows the user to combine two or more sequences to produce
364405
// values of a Cartesian product of those sequences' elements.
365406
//
@@ -407,9 +448,8 @@ inline internal::ParamGenerator<bool> Bool() { return Values(false, true); }
407448
template <typename... T>
408449
internal::ParamGenerator<std::tuple<T...>> Combine(
409450
internal::ParamGenerator<T>&&... generators) {
410-
return internal::ParamGenerator<std::tuple<T...>>(
411-
new internal::CartesianProductGenerator<std::tuple<T...>, T...>(
412-
std::forward<decltype(generators)>(generators)...));
451+
return CombineAs<std::tuple<T...>, T...>(
452+
std::forward<decltype(generators)>(generators)...);
413453
}
414454

415455
// ConvertGenerator() wraps a parameter generator in order to cast each produced

googletest/include/gtest/internal/gtest-param-util.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,8 @@ class CartesianProductGenerator : public ParamGeneratorInterface<R> {
902902

903903
void ComputeCurrentValue() {
904904
if (!AtEnd())
905-
current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...);
905+
current_value_ =
906+
std::make_shared<ParamType>(ParamType{*std::get<I>(current_)...});
906907
}
907908
bool AtEnd() const {
908909
bool at_end = false;

googletest/test/googletest-param-test-test.cc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,70 @@ TEST(ConvertTest, NonDefaultConstructAssign) {
588588
EXPECT_TRUE(it == gen.end());
589589
}
590590

591+
TEST(CombineAsTest, DefaultConstructible) {
592+
struct DefaultConstructible {
593+
int x;
594+
std::string s;
595+
596+
bool operator==(const DefaultConstructible& other) const {
597+
return x == other.x && s == other.s;
598+
}
599+
};
600+
601+
static_assert(std::is_default_constructible_v<DefaultConstructible>);
602+
ParamGenerator<DefaultConstructible> gen =
603+
testing::CombineAs<DefaultConstructible>(Values(0, 1), Values("A", "B"));
604+
605+
DefaultConstructible expected_values[] = {
606+
{0, "A"}, {0, "B"}, {1, "A"}, {1, "B"}};
607+
VerifyGenerator(gen, expected_values);
608+
}
609+
610+
TEST(CombineAsTest, NonDefaultConstructible) {
611+
class NonDefaultConstructible {
612+
public:
613+
NonDefaultConstructible(const int i_arg, std::string s_arg)
614+
: i_(i_arg), s_(std::move(s_arg)) {}
615+
616+
bool operator==(const NonDefaultConstructible& other) const {
617+
return i_ == other.i_ && s_ == other.s_;
618+
}
619+
620+
private:
621+
int i_;
622+
std::string s_;
623+
};
624+
625+
static_assert(!std::is_default_constructible_v<NonDefaultConstructible>);
626+
ParamGenerator<NonDefaultConstructible> gen =
627+
testing::CombineAs<NonDefaultConstructible>(Values(0, 1),
628+
Values("A", "B"));
629+
630+
NonDefaultConstructible expected_values[] = {
631+
{0, "A"}, {0, "B"}, {1, "A"}, {1, "B"}};
632+
VerifyGenerator(gen, expected_values);
633+
}
634+
635+
TEST(CombineAsTest, CopyConstructible) {
636+
struct CopyConstructible {
637+
CopyConstructible(const CopyConstructible& other) = default;
638+
639+
bool operator==(const CopyConstructible& other) const {
640+
return x == other.x && s == other.s;
641+
}
642+
643+
int x;
644+
std::string s;
645+
};
646+
647+
static_assert(std::is_copy_constructible_v<CopyConstructible>);
648+
ParamGenerator<CopyConstructible> gen = testing::CombineAs<CopyConstructible>(
649+
Values(CopyConstructible{0, "A"}, CopyConstructible{1, "B"}));
650+
CopyConstructible expected_values[] = {CopyConstructible{0, "A"},
651+
CopyConstructible{1, "B"}};
652+
VerifyGenerator(gen, expected_values);
653+
}
654+
591655
TEST(ConvertTest, WithConverterLambdaAndDeducedType) {
592656
const ParamGenerator<ConstructFromT<int8_t>> gen =
593657
ConvertGenerator(Values("0", std::string("1")), [](const std::string& s) {

0 commit comments

Comments
 (0)