mirror of
https://github.com/google/googletest.git
synced 2025-12-06 08:46:50 +08:00
Compare commits
7 Commits
96d7a8df73
...
d3be365fbb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3be365fbb | ||
|
|
94f19b4a03 | ||
|
|
18172295df | ||
|
|
cb67f16d48 | ||
|
|
7049d96dd7 | ||
|
|
d3414c2c46 | ||
|
|
ceeca5fcea |
@ -103,14 +103,15 @@ 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. |
|
||||
| `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)`. |
|
||||
| `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`. |
|
||||
| `ConvertGenerator<T>(g)` or `ConvertGenerator(g, func)` | Yields values generated by generator `g`, `static_cast` from `T`. (Note: `T` might not be what you expect. See [*Using ConvertGenerator*](#using-convertgenerator) below.) The second overload uses `func` to perform the conversion. |
|
||||
| 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. |
|
||||
| `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)`. |
|
||||
| `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`. |
|
||||
| `CombineAs<R>(g1, g2, ..., gN)` | Yields as `R` *n*-instances all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
|
||||
| `ConvertGenerator<T>(g)` or `ConvertGenerator(g, func)` | Yields values generated by generator `g`, `static_cast` from `T`. (Note: `T` might not be what you expect. See [*Using ConvertGenerator*](#using-convertgenerator) below.) The second overload uses `func` to perform the conversion. |
|
||||
|
||||
The optional last argument *`name_generator`* is a function or functor that
|
||||
generates custom test name suffixes based on the test parameters. The function
|
||||
@ -234,6 +235,24 @@ To overcome this problem you can specify the generated type explicitly:
|
||||
dangling reference because the type deduction strips off the reference and the
|
||||
`const`).
|
||||
|
||||
###### Using `CombineAs`
|
||||
|
||||
If you think the code above is too complicated, and you do not want to deal
|
||||
with tuples, you may want to use `CombineAs<R>()` which works like a combination
|
||||
of `Combine()` + `ConvertGenerator()` + tuple unpacking function.
|
||||
|
||||
```cpp
|
||||
// The fixture's parameter type.
|
||||
class MyParam {
|
||||
public:
|
||||
MyParam(int, bool);
|
||||
...
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite,
|
||||
CombineAs<MyParam>(Values(1, 1.2), Bool()));
|
||||
```
|
||||
|
||||
### TYPED_TEST_SUITE {#TYPED_TEST_SUITE}
|
||||
|
||||
`TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`
|
||||
|
||||
@ -15,7 +15,7 @@ variety of googletest features.
|
||||
derived fixtures.
|
||||
* Sample #6 demonstrates type-parameterized tests.
|
||||
* Sample #7 teaches the basics of value-parameterized tests.
|
||||
* Sample #8 shows using `Combine()` in value-parameterized tests.
|
||||
* Sample #8 shows using `Combine()` and `CombineAs<R>()` in value-parameterized tests.
|
||||
* Sample #9 shows use of the listener API to modify Google Test's console
|
||||
output and the use of its reflection API to inspect test results.
|
||||
* Sample #10 shows use of the listener API to implement a primitive memory
|
||||
|
||||
@ -174,6 +174,7 @@ TEST_P(DerivedTest, DoesBlah) {
|
||||
|
||||
#endif // 0
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
@ -332,9 +333,10 @@ internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
|
||||
//
|
||||
//
|
||||
template <typename... T>
|
||||
internal::ValueArray<T...> Values(T... v) {
|
||||
return internal::ValueArray<T...>(std::move(v)...);
|
||||
template <typename... Ts>
|
||||
internal::ParamGenerator<std::common_type_t<Ts...>> Values(Ts... vs) {
|
||||
return ValuesIn(
|
||||
std::array<std::common_type_t<Ts...>, sizeof...(Ts)>{std::move(vs)...});
|
||||
}
|
||||
|
||||
// Bool() allows generating tests with parameters in a set of (false, true).
|
||||
@ -359,6 +361,47 @@ internal::ValueArray<T...> Values(T... v) {
|
||||
//
|
||||
inline internal::ParamGenerator<bool> 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<MyClass>(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<Animal> {...};
|
||||
//
|
||||
// TEST_P(AnimalTest, AnimalLooksNice) {...}
|
||||
//
|
||||
// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest,
|
||||
// CombineAs<Animal>(Values("cat", "dog"),
|
||||
// Values(BLACK, WHITE)));
|
||||
//
|
||||
template <typename R, typename... T>
|
||||
internal::ParamGenerator<R> CombineAs(
|
||||
internal::ParamGenerator<T>&&... generators) {
|
||||
return internal::ParamGenerator<R>(
|
||||
new internal::CartesianProductGenerator<R, T...>(
|
||||
std::forward<decltype(generators)>(generators)...));
|
||||
}
|
||||
|
||||
// Combine() allows the user to combine two or more sequences to produce
|
||||
// values of a Cartesian product of those sequences' elements.
|
||||
//
|
||||
@ -403,9 +446,11 @@ inline internal::ParamGenerator<bool> Bool() { return Values(false, true); }
|
||||
// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest,
|
||||
// Combine(Bool(), Bool()));
|
||||
//
|
||||
template <typename... Generator>
|
||||
internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
|
||||
return internal::CartesianProductHolder<Generator...>(g...);
|
||||
template <typename... T>
|
||||
internal::ParamGenerator<std::tuple<T...>> Combine(
|
||||
internal::ParamGenerator<T>&&... generators) {
|
||||
return CombineAs<std::tuple<T...>, T...>(
|
||||
std::forward<decltype(generators)>(generators)...);
|
||||
}
|
||||
|
||||
// ConvertGenerator() wraps a parameter generator in order to cast each produced
|
||||
|
||||
@ -61,15 +61,15 @@
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest-assertion-result.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-death-test.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-matchers.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-message.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-param-test.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-printers.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-test-part.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-typed-test.h" // IWYU pragma: export
|
||||
#include "gtest/gtest_pred_impl.h" // IWYU pragma: export
|
||||
#include "gtest/gtest_prod.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-death-test.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-matchers.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-message.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-param-test.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-printers.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-test-part.h" // IWYU pragma: export
|
||||
#include "gtest/gtest-typed-test.h" // IWYU pragma: export
|
||||
#include "gtest/gtest_pred_impl.h" // IWYU pragma: export
|
||||
#include "gtest/gtest_prod.h" // IWYU pragma: export
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
@ -1664,7 +1664,8 @@ class GTEST_API_ AssertHelper {
|
||||
// the GetParam() method.
|
||||
//
|
||||
// Use it with one of the parameter generator defining functions, like Range(),
|
||||
// Values(), ValuesIn(), Bool(), Combine(), and ConvertGenerator<T>().
|
||||
// Values(), ValuesIn(), Bool(), Combine(), CombineAs<R>(), and
|
||||
// ConvertGenerator<T>().
|
||||
//
|
||||
// class FooTest : public ::testing::TestWithParam<int> {
|
||||
// protected:
|
||||
|
||||
@ -180,6 +180,11 @@ class ParamGeneratorInterface {
|
||||
virtual ParamIteratorInterface<T>* End() const = 0;
|
||||
};
|
||||
|
||||
template <class GeneratedT,
|
||||
typename StdFunction =
|
||||
std::function<const GeneratedT&(const GeneratedT&)>>
|
||||
class ParamConverterGenerator;
|
||||
|
||||
// Wraps ParamGeneratorInterface<T> and provides general generator syntax
|
||||
// compatible with the STL Container concept.
|
||||
// This class implements copy initialization semantics and the contained
|
||||
@ -201,6 +206,11 @@ class ParamGenerator {
|
||||
iterator begin() const { return iterator(impl_->Begin()); }
|
||||
iterator end() const { return iterator(impl_->End()); }
|
||||
|
||||
template <typename R>
|
||||
operator ParamGenerator<R>() {
|
||||
return ParamConverterGenerator<T>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<const ParamGeneratorInterface<T>> impl_;
|
||||
};
|
||||
@ -796,39 +806,15 @@ internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
const Container& container);
|
||||
|
||||
namespace internal {
|
||||
// Used in the Values() function to provide polymorphic capabilities.
|
||||
|
||||
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4100)
|
||||
|
||||
template <typename... Ts>
|
||||
class ValueArray {
|
||||
template <typename R, typename... T>
|
||||
class CartesianProductGenerator : public ParamGeneratorInterface<R> {
|
||||
public:
|
||||
explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {}
|
||||
using ParamType = R;
|
||||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const { // NOLINT
|
||||
return ValuesIn(MakeVector<T>(std::make_index_sequence<sizeof...(Ts)>()));
|
||||
}
|
||||
explicit CartesianProductGenerator(ParamGenerator<T>&&... g)
|
||||
: generators_(std::forward<decltype(g)>(g)...) {}
|
||||
|
||||
private:
|
||||
template <typename T, size_t... I>
|
||||
std::vector<T> MakeVector(std::index_sequence<I...>) const {
|
||||
return std::vector<T>{static_cast<T>(v_.template Get<I>())...};
|
||||
}
|
||||
|
||||
FlatTuple<Ts...> v_;
|
||||
};
|
||||
|
||||
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4100
|
||||
|
||||
template <typename... T>
|
||||
class CartesianProductGenerator
|
||||
: public ParamGeneratorInterface<::std::tuple<T...>> {
|
||||
public:
|
||||
typedef ::std::tuple<T...> ParamType;
|
||||
|
||||
CartesianProductGenerator(const std::tuple<ParamGenerator<T>...>& g)
|
||||
: generators_(g) {}
|
||||
~CartesianProductGenerator() override = default;
|
||||
|
||||
ParamIteratorInterface<ParamType>* Begin() const override {
|
||||
@ -916,7 +902,8 @@ class CartesianProductGenerator
|
||||
|
||||
void ComputeCurrentValue() {
|
||||
if (!AtEnd())
|
||||
current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...);
|
||||
current_value_ =
|
||||
std::make_shared<ParamType>(ParamType{*std::get<I>(current_)...});
|
||||
}
|
||||
bool AtEnd() const {
|
||||
bool at_end = false;
|
||||
@ -938,20 +925,6 @@ class CartesianProductGenerator
|
||||
std::tuple<ParamGenerator<T>...> generators_;
|
||||
};
|
||||
|
||||
template <class... Gen>
|
||||
class CartesianProductHolder {
|
||||
public:
|
||||
CartesianProductHolder(const Gen&... g) : generators_(g...) {}
|
||||
template <typename... T>
|
||||
operator ParamGenerator<::std::tuple<T...>>() const {
|
||||
return ParamGenerator<::std::tuple<T...>>(
|
||||
new CartesianProductGenerator<T...>(generators_));
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<Gen...> generators_;
|
||||
};
|
||||
|
||||
template <typename From, typename To, typename Func>
|
||||
class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
||||
public:
|
||||
@ -1020,9 +993,7 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
||||
Func converter_;
|
||||
}; // class ParamGeneratorConverter
|
||||
|
||||
template <class GeneratedT,
|
||||
typename StdFunction =
|
||||
std::function<const GeneratedT&(const GeneratedT&)>>
|
||||
template <class GeneratedT, typename StdFunction>
|
||||
class ParamConverterGenerator {
|
||||
public:
|
||||
ParamConverterGenerator(ParamGenerator<GeneratedT> g) // NOLINT
|
||||
|
||||
@ -81,6 +81,7 @@ class HybridPrimeTable : public PrimeTable {
|
||||
|
||||
using ::testing::Bool;
|
||||
using ::testing::Combine;
|
||||
using ::testing::CombineAs;
|
||||
using ::testing::TestWithParam;
|
||||
using ::testing::Values;
|
||||
|
||||
@ -151,4 +152,45 @@ TEST_P(PrimeTableTest, CanGetNextPrime) {
|
||||
INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, PrimeTableTest,
|
||||
Combine(Bool(), Values(1, 10)));
|
||||
|
||||
// But now you look at the PrimeTableTest and you think dealing with std::tuple
|
||||
// requires some boilerplate to unwrap it. You can use combined parameters of
|
||||
// custom types easily with help of CombineAs<R>().
|
||||
struct WellTypedPrimeTableTestParams {
|
||||
bool force_on_the_fly;
|
||||
int max_precalculated;
|
||||
};
|
||||
|
||||
class WellTypedPrimeTableTest
|
||||
: public TestWithParam<WellTypedPrimeTableTestParams> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// It is possible to avoid destructuring of the std::tuple if we use struct
|
||||
// as the test parameter type.
|
||||
table_ = new HybridPrimeTable(GetParam().force_on_the_fly,
|
||||
GetParam().max_precalculated);
|
||||
}
|
||||
void TearDown() override {
|
||||
delete table_;
|
||||
table_ = nullptr;
|
||||
}
|
||||
HybridPrimeTable* table_ = nullptr;
|
||||
};
|
||||
|
||||
// The tests are made the same way as above
|
||||
TEST_P(WellTypedPrimeTableTest, CanGetNextPrime) {
|
||||
EXPECT_EQ(2, table_->GetNextPrime(0));
|
||||
EXPECT_EQ(3, table_->GetNextPrime(2));
|
||||
EXPECT_EQ(5, table_->GetNextPrime(3));
|
||||
EXPECT_EQ(7, table_->GetNextPrime(5));
|
||||
EXPECT_EQ(11, table_->GetNextPrime(7));
|
||||
EXPECT_EQ(131, table_->GetNextPrime(128));
|
||||
}
|
||||
|
||||
// Here we instantiate our tests with combined parameters and straightforward
|
||||
// typing. CombineAs<R>() allows you to generate all possible combinations of
|
||||
// values the same way as Combine() does, but also converts them to the desired
|
||||
// type.
|
||||
INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, WellTypedPrimeTableTest,
|
||||
CombineAs<WellTypedPrimeTableTestParams>(Bool(), Values(1, 10)));
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -588,6 +588,75 @@ 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<DefaultConstructible>);
|
||||
ParamGenerator<DefaultConstructible> gen =
|
||||
testing::CombineAs<DefaultConstructible>(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<NonDefaultConstructible>);
|
||||
ParamGenerator<NonDefaultConstructible> gen =
|
||||
testing::CombineAs<NonDefaultConstructible>(Values(0, 1),
|
||||
Values("A", "B"));
|
||||
|
||||
NonDefaultConstructible expected_values[] = {
|
||||
{0, "A"}, {0, "B"}, {1, "A"}, {1, "B"}};
|
||||
VerifyGenerator(gen, expected_values);
|
||||
}
|
||||
|
||||
TEST(CombineAsTest, CopyConstructible) {
|
||||
class CopyConstructible {
|
||||
public:
|
||||
CopyConstructible(const CopyConstructible& other) = default;
|
||||
|
||||
CopyConstructible(const int i_arg, std::string s_arg)
|
||||
: i_(i_arg), s_(std::move(s_arg)) {}
|
||||
|
||||
bool operator==(const CopyConstructible& other) const {
|
||||
return i_ == other.i_ && s_ == other.s_;
|
||||
}
|
||||
|
||||
private:
|
||||
int i_;
|
||||
std::string s_;
|
||||
};
|
||||
|
||||
static_assert(std::is_copy_constructible_v<CopyConstructible>);
|
||||
ParamGenerator<CopyConstructible> gen = testing::CombineAs<CopyConstructible>(
|
||||
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<ConstructFromT<int8_t>> gen =
|
||||
ConvertGenerator(Values("0", std::string("1")), [](const std::string& s) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user