Merge pull request #3967 from BMBurstein:custom_type_combine
PiperOrigin-RevId: 478775323 Change-Id: I92231bb8edd8e01b9b7cbe445c43dcf84f458521
This commit is contained in:
commit
8c4dc11539
@ -103,12 +103,21 @@ namespace:
|
||||
<span id="param-generators"></span>
|
||||
|
||||
| Parameter Generator | Behavior |
|
||||
| ------------------- | ---------------------------------------------------- |
|
||||
| `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. |
|
||||
| ---------------------------- | -------------------------------------------- |
|
||||
| `Range(begin, end [, step])` | Yields values `{begin, begin+step, |
|
||||
: : begin+step+step, ...}`. The values do not :
|
||||
: : include `end`. `step` defaults to 1. :
|
||||
| `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. |
|
||||
| `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. |
|
||||
| `ValuesIn(container)` or | Yields values from a C-style array, an |
|
||||
: `ValuesIn(begin,end)` : STL-style container, or an iterator range :
|
||||
: : `[begin, end)`. :
|
||||
| `Bool()` | Yields sequence `{false, true}`. |
|
||||
| `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
|
||||
| `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all |
|
||||
: : combinations (Cartesian product) of the :
|
||||
: : values generated by the given *n* generators :
|
||||
: : `g1`, `g2`, ..., `gN`. :
|
||||
| `ConvertGenerator<T>(g)` | Yields values generated by generator `g`, |
|
||||
: : `static_cast` to `T`. :
|
||||
|
||||
The optional last argument *`name_generator`* is a function or functor that
|
||||
generates custom test name suffixes based on the test parameters. The function
|
||||
|
@ -407,6 +407,46 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
|
||||
return internal::CartesianProductHolder<Generator...>(g...);
|
||||
}
|
||||
|
||||
// ConvertGenerator() wraps a parameter generator in order to cast each prduced
|
||||
// value through a known type before supplying it to the test suite
|
||||
//
|
||||
// Synopsis:
|
||||
// ConvertGenerator<T>(gen)
|
||||
// - returns a generator producing the same elements as generated by gen, but
|
||||
// each element is static_cast to type T before being returned
|
||||
//
|
||||
// It is useful when using the Combine() function to get the generated
|
||||
// parameters in a custom type instead of std::tuple
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// This will instantiate tests in test suite AnimalTest each one with
|
||||
// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
|
||||
// tuple("dog", BLACK), and tuple("dog", WHITE):
|
||||
//
|
||||
// enum Color { BLACK, GRAY, WHITE };
|
||||
// struct ParamType {
|
||||
// using TupleT = std::tuple<const char*, Color>;
|
||||
// std::string animal;
|
||||
// Color color;
|
||||
// ParamType(TupleT t) : animal(std::get<0>(t)), color(std::get<1>(t)) {}
|
||||
// };
|
||||
// class AnimalTest
|
||||
// : public testing::TestWithParam<ParamType> {...};
|
||||
//
|
||||
// TEST_P(AnimalTest, AnimalLooksNice) {...}
|
||||
//
|
||||
// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest,
|
||||
// ConvertGenerator<ParamType::TupleT>(
|
||||
// Combine(Values("cat", "dog"),
|
||||
// Values(BLACK, WHITE))));
|
||||
//
|
||||
template <typename T>
|
||||
internal::ParamConverterGenerator<T> ConvertGenerator(
|
||||
internal::ParamGenerator<T> gen) {
|
||||
return internal::ParamConverterGenerator<T>(gen);
|
||||
}
|
||||
|
||||
#define TEST_P(test_suite_name, test_name) \
|
||||
class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
|
||||
: public test_suite_name, private ::testing::internal::GTestNonCopyable {\
|
||||
|
@ -1636,7 +1636,7 @@ class GTEST_API_ AssertHelper {
|
||||
// the GetParam() method.
|
||||
//
|
||||
// Use it with one of the parameter generator defining functions, like Range(),
|
||||
// Values(), ValuesIn(), Bool(), and Combine().
|
||||
// Values(), ValuesIn(), Bool(), Combine(), and ConvertGenerator<T>().
|
||||
//
|
||||
// class FooTest : public ::testing::TestWithParam<int> {
|
||||
// protected:
|
||||
|
@ -950,6 +950,78 @@ class CartesianProductHolder {
|
||||
std::tuple<Gen...> generators_;
|
||||
};
|
||||
|
||||
template <typename From, typename To>
|
||||
class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
||||
public:
|
||||
ParamGeneratorConverter(ParamGenerator<From> gen) // NOLINT
|
||||
: generator_(std::move(gen)) {}
|
||||
|
||||
ParamIteratorInterface<To>* Begin() const override {
|
||||
return new Iterator(this, generator_.begin(), generator_.end());
|
||||
}
|
||||
ParamIteratorInterface<To>* End() const override {
|
||||
return new Iterator(this, generator_.end(), generator_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
class Iterator : public ParamIteratorInterface<To> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<To>* base, ParamIterator<From> it,
|
||||
ParamIterator<From> end)
|
||||
: base_(base), it_(it), end_(end) {
|
||||
if (it_ != end_) value_ = std::make_shared<To>(static_cast<To>(*it_));
|
||||
}
|
||||
~Iterator() override {}
|
||||
|
||||
const ParamGeneratorInterface<To>* BaseGenerator() const override {
|
||||
return base_;
|
||||
}
|
||||
void Advance() override {
|
||||
++it_;
|
||||
if (it_ != end_) value_ = std::make_shared<To>(static_cast<To>(*it_));
|
||||
}
|
||||
ParamIteratorInterface<To>* Clone() const override {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
const To* Current() const override { return value_.get(); }
|
||||
bool Equals(const ParamIteratorInterface<To>& other) const override {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
const ParamIterator<From> other_it =
|
||||
CheckedDowncastToActualType<const Iterator>(&other)->it_;
|
||||
return it_ == other_it;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other) = default;
|
||||
|
||||
const ParamGeneratorInterface<To>* const base_;
|
||||
ParamIterator<From> it_;
|
||||
ParamIterator<From> end_;
|
||||
std::shared_ptr<To> value_;
|
||||
}; // class ParamGeneratorConverter::Iterator
|
||||
|
||||
ParamGenerator<From> generator_;
|
||||
}; // class ParamGeneratorConverter
|
||||
|
||||
template <class Gen>
|
||||
class ParamConverterGenerator {
|
||||
public:
|
||||
ParamConverterGenerator(ParamGenerator<Gen> g) // NOLINT
|
||||
: generator_(std::move(g)) {}
|
||||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const { // NOLINT
|
||||
return ParamGenerator<T>(new ParamGeneratorConverter<Gen, T>(generator_));
|
||||
}
|
||||
|
||||
private:
|
||||
ParamGenerator<Gen> generator_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
@ -51,6 +52,7 @@ using ::std::vector;
|
||||
using ::testing::AddGlobalTestEnvironment;
|
||||
using ::testing::Bool;
|
||||
using ::testing::Combine;
|
||||
using ::testing::ConvertGenerator;
|
||||
using ::testing::Message;
|
||||
using ::testing::Range;
|
||||
using ::testing::TestWithParam;
|
||||
@ -523,6 +525,64 @@ TEST(CombineTest, NonDefaultConstructAssign) {
|
||||
EXPECT_TRUE(it == gen.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ConstructFromT {
|
||||
public:
|
||||
explicit ConstructFromT(const T& t) : t_(t) {}
|
||||
template <typename... Args,
|
||||
typename std::enable_if<sizeof...(Args) != 1, int>::type = 0>
|
||||
ConstructFromT(Args&&... args) : t_(std::forward<Args>(args)...) {}
|
||||
|
||||
bool operator==(const ConstructFromT& other) const { return other.t_ == t_; }
|
||||
|
||||
const T& get() const { return t_; }
|
||||
|
||||
private:
|
||||
T t_;
|
||||
};
|
||||
|
||||
TEST(ConvertTest, CombineWithTwoParameters) {
|
||||
const char* foo = "foo";
|
||||
const char* bar = "bar";
|
||||
const ParamGenerator<ConstructFromT<std::tuple<const char*, int>>> gen =
|
||||
ConvertGenerator<std::tuple<const char*, int>>(
|
||||
Combine(Values(foo, bar), Values(3, 4)));
|
||||
|
||||
ConstructFromT<std::tuple<const char*, int>> expected_values[] = {
|
||||
{foo, 3}, {foo, 4}, {bar, 3}, {bar, 4}};
|
||||
VerifyGenerator(gen, expected_values);
|
||||
}
|
||||
|
||||
TEST(ConvertTest, NonDefaultConstructAssign) {
|
||||
const ParamGenerator<
|
||||
ConstructFromT<std::tuple<int, NonDefaultConstructAssignString>>>
|
||||
gen = ConvertGenerator<std::tuple<int, NonDefaultConstructAssignString>>(
|
||||
Combine(Values(0, 1), Values(NonDefaultConstructAssignString("A"),
|
||||
NonDefaultConstructAssignString("B"))));
|
||||
|
||||
ParamGenerator<ConstructFromT<
|
||||
std::tuple<int, NonDefaultConstructAssignString>>>::iterator it =
|
||||
gen.begin();
|
||||
|
||||
EXPECT_EQ(0, std::get<0>(it->get()));
|
||||
EXPECT_EQ("A", std::get<1>(it->get()).str());
|
||||
++it;
|
||||
|
||||
EXPECT_EQ(0, std::get<0>(it->get()));
|
||||
EXPECT_EQ("B", std::get<1>(it->get()).str());
|
||||
++it;
|
||||
|
||||
EXPECT_EQ(1, std::get<0>(it->get()));
|
||||
EXPECT_EQ("A", std::get<1>(it->get()).str());
|
||||
++it;
|
||||
|
||||
EXPECT_EQ(1, std::get<0>(it->get()));
|
||||
EXPECT_EQ("B", std::get<1>(it->get()).str());
|
||||
++it;
|
||||
|
||||
EXPECT_TRUE(it == gen.end());
|
||||
}
|
||||
|
||||
// Tests that an generator produces correct sequence after being
|
||||
// assigned from another generator.
|
||||
TEST(ParamGeneratorTest, AssignmentWorks) {
|
||||
|
Loading…
Reference in New Issue
Block a user