mirror of
https://github.com/google/googletest.git
synced 2025-03-27 22:49:21 +00:00
Add a testing::ConvertGenerator
overload that accepts a converting functor. This allows the use of classes that do not have a converting ctor to the desired type.
PiperOrigin-RevId: 733383835 Change-Id: I6fbf79db0509b3d4fe8305a83ed47fceaa820e47
This commit is contained in:
parent
24a9e940d4
commit
e88cb95b92
@ -110,7 +110,7 @@ namespace:
|
|||||||
| `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 `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}`. |
|
| `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`. |
|
| `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
|
The optional last argument *`name_generator`* is a function or functor that
|
||||||
generates custom test name suffixes based on the test parameters. The function
|
generates custom test name suffixes based on the test parameters. The function
|
||||||
@ -137,6 +137,103 @@ For more information, see
|
|||||||
See also
|
See also
|
||||||
[`GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST`](#GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST).
|
[`GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST`](#GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST).
|
||||||
|
|
||||||
|
###### Using `ConvertGenerator`
|
||||||
|
|
||||||
|
The functions listed in the table above appear to return generators that create
|
||||||
|
values of the desired types, but this is not generally the case. Rather, they
|
||||||
|
typically return factory objects that convert to the the desired generators.
|
||||||
|
This affords some flexibility in allowing you to specify values of types that
|
||||||
|
are different from, yet implicitly convertible to, the actual parameter type
|
||||||
|
required by your fixture class.
|
||||||
|
|
||||||
|
For example, you can do the following with a fixture that requires an `int`
|
||||||
|
parameter:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite,
|
||||||
|
testing::Values(1, 1.2)); // Yes, Values() supports heterogeneous argument types.
|
||||||
|
```
|
||||||
|
|
||||||
|
It might seem obvious that `1.2` — a `double` — will be converted to
|
||||||
|
an `int` but in actuality it requires some template gymnastics involving the
|
||||||
|
indirection described in the previous paragraph.
|
||||||
|
|
||||||
|
What if your parameter type is not implicitly convertible from the generated
|
||||||
|
type but is *explicitly* convertible? There will be no automatic conversion, but
|
||||||
|
you can force it by applying `ConvertGenerator<T>`. The compiler can
|
||||||
|
automatically deduce the target type (your fixture's parameter type), but
|
||||||
|
because of the aforementioned indirection it cannot decide what the generated
|
||||||
|
type should be. You need to tell it, by providing the type `T` explicitly. Thus
|
||||||
|
`T` should not be your fixture's parameter type, but rather an intermediate type
|
||||||
|
that is supported by the factory object, and which can be `static_cast` to the
|
||||||
|
fixture's parameter type:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// The fixture's parameter type.
|
||||||
|
class MyParam {
|
||||||
|
public:
|
||||||
|
// Explicit converting ctor.
|
||||||
|
explicit MyParam(const std::tuple<int, bool>& t);
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite,
|
||||||
|
ConvertGenerator<std::tuple<int, bool>>(Combine(Values(0.1, 1.2), Bool())));
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example `Combine` supports the generation of `std::tuple<int, bool>>`
|
||||||
|
objects (even though the provided values for the first tuple element are
|
||||||
|
`double`s) and those `tuple`s get converted into `MyParam` objects by virtue of
|
||||||
|
the call to `ConvertGenerator`.
|
||||||
|
|
||||||
|
For parameter types that are not convertible from the generated types you can
|
||||||
|
provide a callable that does the conversion. The callable accepts an object of
|
||||||
|
the generated type and returns an object of the fixture's parameter type. The
|
||||||
|
generated type can often be deduced by the compiler from the callable's call
|
||||||
|
signature so you do not usually need specify it explicitly (but see a caveat
|
||||||
|
below).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// The fixture's parameter type.
|
||||||
|
class MyParam {
|
||||||
|
public:
|
||||||
|
MyParam(int, bool);
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite,
|
||||||
|
ConvertGenerator(Combine(Values(1, 1.2), Bool()),
|
||||||
|
[](const std::tuple<int i, bool>& t){
|
||||||
|
const auto [i, b] = t;
|
||||||
|
return MyParam(i, b);
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
The callable may be anything that can be used to initialize a `std::function`
|
||||||
|
with the appropriate call signature. Note the callable's return object gets
|
||||||
|
`static_cast` to the fixture's parameter type, so it does not have to be of that
|
||||||
|
exact type, only convertible to it.
|
||||||
|
|
||||||
|
**Caveat:** Consider the following example.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite,
|
||||||
|
ConvertGenerator(Values(std::string("s")), [](std::string_view s) { ... }));
|
||||||
|
```
|
||||||
|
|
||||||
|
The `string` argument gets copied into the factory object returned by `Values`.
|
||||||
|
Then, because the generated type deduced from the lambda is `string_view`, the
|
||||||
|
factory object spawns a generator that holds a `string_view` referencing that
|
||||||
|
`string`. Unfortunately, by the time this generator gets invoked, the factory
|
||||||
|
object is gone and the `string_view` is dangling.
|
||||||
|
|
||||||
|
To overcome this problem you can specify the generated type explicitly:
|
||||||
|
`ConvertGenerator<std::string>(Values(std::string("s")), [](std::string_view s)
|
||||||
|
{ ... })`. Alternatively, you can change the lambda's signature to take a
|
||||||
|
`std::string` or a `const std::string&` (the latter will not leave you with a
|
||||||
|
dangling reference because the type deduction strips off the reference and the
|
||||||
|
`const`).
|
||||||
|
|
||||||
### TYPED_TEST_SUITE {#TYPED_TEST_SUITE}
|
### TYPED_TEST_SUITE {#TYPED_TEST_SUITE}
|
||||||
|
|
||||||
`TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`
|
`TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`
|
||||||
|
@ -174,6 +174,7 @@ TEST_P(DerivedTest, DoesBlah) {
|
|||||||
|
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -413,7 +414,8 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
|
|||||||
// Synopsis:
|
// Synopsis:
|
||||||
// ConvertGenerator<T>(gen)
|
// ConvertGenerator<T>(gen)
|
||||||
// - returns a generator producing the same elements as generated by gen, but
|
// - returns a generator producing the same elements as generated by gen, but
|
||||||
// each element is static_cast to type T before being returned
|
// each T-typed element is static_cast to a type deduced from the interface
|
||||||
|
// that accepts this generator, and then returned
|
||||||
//
|
//
|
||||||
// It is useful when using the Combine() function to get the generated
|
// It is useful when using the Combine() function to get the generated
|
||||||
// parameters in a custom type instead of std::tuple
|
// parameters in a custom type instead of std::tuple
|
||||||
@ -441,10 +443,65 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
|
|||||||
// Combine(Values("cat", "dog"),
|
// Combine(Values("cat", "dog"),
|
||||||
// Values(BLACK, WHITE))));
|
// Values(BLACK, WHITE))));
|
||||||
//
|
//
|
||||||
template <typename T>
|
template <typename RequestedT>
|
||||||
internal::ParamConverterGenerator<T> ConvertGenerator(
|
internal::ParamConverterGenerator<RequestedT> ConvertGenerator(
|
||||||
internal::ParamGenerator<T> gen) {
|
internal::ParamGenerator<RequestedT> gen) {
|
||||||
return internal::ParamConverterGenerator<T>(gen);
|
return internal::ParamConverterGenerator<RequestedT>(std::move(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
// As above, but takes a callable as a second argument. The callable converts
|
||||||
|
// the generated parameter to the test fixture's parameter type. This allows you
|
||||||
|
// to use a parameter type that does not have a converting constructor from the
|
||||||
|
// generated type.
|
||||||
|
//
|
||||||
|
// 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 {
|
||||||
|
// std::string animal;
|
||||||
|
// Color color;
|
||||||
|
// };
|
||||||
|
// class AnimalTest
|
||||||
|
// : public testing::TestWithParam<ParamType> {...};
|
||||||
|
//
|
||||||
|
// TEST_P(AnimalTest, AnimalLooksNice) {...}
|
||||||
|
//
|
||||||
|
// INSTANTIATE_TEST_SUITE_P(
|
||||||
|
// AnimalVariations, AnimalTest,
|
||||||
|
// ConvertGenerator(Combine(Values("cat", "dog"), Values(BLACK, WHITE)),
|
||||||
|
// [](std::tuple<std::string, Color> t) {
|
||||||
|
// return ParamType{.animal = std::get<0>(t),
|
||||||
|
// .color = std::get<1>(t)};
|
||||||
|
// }));
|
||||||
|
//
|
||||||
|
template <typename T, int&... ExplicitArgumentBarrier, typename Gen,
|
||||||
|
typename Func,
|
||||||
|
typename StdFunction = decltype(std::function(std::declval<Func>()))>
|
||||||
|
internal::ParamConverterGenerator<T, StdFunction> ConvertGenerator(Gen&& gen,
|
||||||
|
Func&& f) {
|
||||||
|
return internal::ParamConverterGenerator<T, StdFunction>(
|
||||||
|
std::forward<Gen>(gen), std::forward<Func>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// As above, but infers the T from the supplied std::function instead of
|
||||||
|
// having the caller specify it.
|
||||||
|
template <int&... ExplicitArgumentBarrier, typename Gen, typename Func,
|
||||||
|
typename StdFunction = decltype(std::function(std::declval<Func>()))>
|
||||||
|
auto ConvertGenerator(Gen&& gen, Func&& f) {
|
||||||
|
constexpr bool is_single_arg_std_function =
|
||||||
|
internal::IsSingleArgStdFunction<StdFunction>::value;
|
||||||
|
if constexpr (is_single_arg_std_function) {
|
||||||
|
return ConvertGenerator<
|
||||||
|
typename internal::FuncSingleParamType<StdFunction>::type>(
|
||||||
|
std::forward<Gen>(gen), std::forward<Func>(f));
|
||||||
|
} else {
|
||||||
|
static_assert(is_single_arg_std_function,
|
||||||
|
"The call signature must contain a single argument.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEST_P(test_suite_name, test_name) \
|
#define TEST_P(test_suite_name, test_name) \
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -529,8 +530,7 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase {
|
|||||||
// prefix). test_base_name is the name of an individual test without
|
// prefix). test_base_name is the name of an individual test without
|
||||||
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
||||||
// test suite base name and DoBar is test base name.
|
// test suite base name and DoBar is test base name.
|
||||||
void AddTestPattern(const char*,
|
void AddTestPattern(const char*, const char* test_base_name,
|
||||||
const char* test_base_name,
|
|
||||||
TestMetaFactoryBase<ParamType>* meta_factory,
|
TestMetaFactoryBase<ParamType>* meta_factory,
|
||||||
CodeLocation code_location) {
|
CodeLocation code_location) {
|
||||||
tests_.emplace_back(
|
tests_.emplace_back(
|
||||||
@ -952,11 +952,11 @@ class CartesianProductHolder {
|
|||||||
std::tuple<Gen...> generators_;
|
std::tuple<Gen...> generators_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename From, typename To>
|
template <typename From, typename To, typename Func>
|
||||||
class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
||||||
public:
|
public:
|
||||||
ParamGeneratorConverter(ParamGenerator<From> gen) // NOLINT
|
ParamGeneratorConverter(ParamGenerator<From> gen, Func converter) // NOLINT
|
||||||
: generator_(std::move(gen)) {}
|
: generator_(std::move(gen)), converter_(std::move(converter)) {}
|
||||||
|
|
||||||
ParamIteratorInterface<To>* Begin() const override {
|
ParamIteratorInterface<To>* Begin() const override {
|
||||||
return new Iterator(this, generator_.begin(), generator_.end());
|
return new Iterator(this, generator_.begin(), generator_.end());
|
||||||
@ -965,13 +965,21 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
|||||||
return new Iterator(this, generator_.end(), generator_.end());
|
return new Iterator(this, generator_.end(), generator_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the std::function wrapping the user-supplied converter callable. It
|
||||||
|
// is used by the iterator (see class Iterator below) to convert the object
|
||||||
|
// (of type FROM) returned by the ParamGenerator to an object of a type that
|
||||||
|
// can be static_cast to type TO.
|
||||||
|
const Func& TypeConverter() const { return converter_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Iterator : public ParamIteratorInterface<To> {
|
class Iterator : public ParamIteratorInterface<To> {
|
||||||
public:
|
public:
|
||||||
Iterator(const ParamGeneratorInterface<To>* base, ParamIterator<From> it,
|
Iterator(const ParamGeneratorConverter* base, ParamIterator<From> it,
|
||||||
ParamIterator<From> end)
|
ParamIterator<From> end)
|
||||||
: base_(base), it_(it), end_(end) {
|
: base_(base), it_(it), end_(end) {
|
||||||
if (it_ != end_) value_ = std::make_shared<To>(static_cast<To>(*it_));
|
if (it_ != end_)
|
||||||
|
value_ =
|
||||||
|
std::make_shared<To>(static_cast<To>(base->TypeConverter()(*it_)));
|
||||||
}
|
}
|
||||||
~Iterator() override = default;
|
~Iterator() override = default;
|
||||||
|
|
||||||
@ -980,7 +988,9 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
|||||||
}
|
}
|
||||||
void Advance() override {
|
void Advance() override {
|
||||||
++it_;
|
++it_;
|
||||||
if (it_ != end_) value_ = std::make_shared<To>(static_cast<To>(*it_));
|
if (it_ != end_)
|
||||||
|
value_ =
|
||||||
|
std::make_shared<To>(static_cast<To>(base_->TypeConverter()(*it_)));
|
||||||
}
|
}
|
||||||
ParamIteratorInterface<To>* Clone() const override {
|
ParamIteratorInterface<To>* Clone() const override {
|
||||||
return new Iterator(*this);
|
return new Iterator(*this);
|
||||||
@ -1000,30 +1010,54 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
|||||||
private:
|
private:
|
||||||
Iterator(const Iterator& other) = default;
|
Iterator(const Iterator& other) = default;
|
||||||
|
|
||||||
const ParamGeneratorInterface<To>* const base_;
|
const ParamGeneratorConverter* const base_;
|
||||||
ParamIterator<From> it_;
|
ParamIterator<From> it_;
|
||||||
ParamIterator<From> end_;
|
ParamIterator<From> end_;
|
||||||
std::shared_ptr<To> value_;
|
std::shared_ptr<To> value_;
|
||||||
}; // class ParamGeneratorConverter::Iterator
|
}; // class ParamGeneratorConverter::Iterator
|
||||||
|
|
||||||
ParamGenerator<From> generator_;
|
ParamGenerator<From> generator_;
|
||||||
|
Func converter_;
|
||||||
}; // class ParamGeneratorConverter
|
}; // class ParamGeneratorConverter
|
||||||
|
|
||||||
template <class Gen>
|
template <class GeneratedT,
|
||||||
|
typename StdFunction =
|
||||||
|
std::function<const GeneratedT&(const GeneratedT&)>>
|
||||||
class ParamConverterGenerator {
|
class ParamConverterGenerator {
|
||||||
public:
|
public:
|
||||||
ParamConverterGenerator(ParamGenerator<Gen> g) // NOLINT
|
ParamConverterGenerator(ParamGenerator<GeneratedT> g) // NOLINT
|
||||||
: generator_(std::move(g)) {}
|
: generator_(std::move(g)), converter_(Identity) {}
|
||||||
|
|
||||||
|
ParamConverterGenerator(ParamGenerator<GeneratedT> g, StdFunction converter)
|
||||||
|
: generator_(std::move(g)), converter_(std::move(converter)) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
operator ParamGenerator<T>() const { // NOLINT
|
operator ParamGenerator<T>() const { // NOLINT
|
||||||
return ParamGenerator<T>(new ParamGeneratorConverter<Gen, T>(generator_));
|
return ParamGenerator<T>(
|
||||||
|
new ParamGeneratorConverter<GeneratedT, T, StdFunction>(generator_,
|
||||||
|
converter_));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ParamGenerator<Gen> generator_;
|
static const GeneratedT& Identity(const GeneratedT& v) { return v; }
|
||||||
|
|
||||||
|
ParamGenerator<GeneratedT> generator_;
|
||||||
|
StdFunction converter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Template to determine the param type of a single-param std::function.
|
||||||
|
template <typename T>
|
||||||
|
struct FuncSingleParamType;
|
||||||
|
template <typename R, typename P>
|
||||||
|
struct FuncSingleParamType<std::function<R(P)>> {
|
||||||
|
using type = std::remove_cv_t<std::remove_reference_t<P>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct IsSingleArgStdFunction : public std::false_type {};
|
||||||
|
template <typename R, typename P>
|
||||||
|
struct IsSingleArgStdFunction<std::function<R(P)>> : public std::true_type {};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
|
@ -35,12 +35,17 @@
|
|||||||
#include "test/googletest-param-test-test.h"
|
#include "test/googletest-param-test-test.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
@ -583,6 +588,71 @@ TEST(ConvertTest, NonDefaultConstructAssign) {
|
|||||||
EXPECT_TRUE(it == gen.end());
|
EXPECT_TRUE(it == gen.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ConvertTest, WithConverterLambdaAndDeducedType) {
|
||||||
|
const ParamGenerator<ConstructFromT<int8_t>> gen =
|
||||||
|
ConvertGenerator(Values("0", std::string("1")), [](const std::string& s) {
|
||||||
|
size_t pos;
|
||||||
|
int64_t value = std::stoll(s, &pos);
|
||||||
|
EXPECT_EQ(pos, s.size());
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0),
|
||||||
|
ConstructFromT<int8_t>(1)};
|
||||||
|
VerifyGenerator(gen, expected_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ConvertTest, WithConverterLambdaAndExplicitType) {
|
||||||
|
auto convert_generator = ConvertGenerator<std::string>(
|
||||||
|
Values("0", std::string("1")), [](std::string_view s) {
|
||||||
|
size_t pos;
|
||||||
|
int64_t value = std::stoll(std::string(s), &pos);
|
||||||
|
EXPECT_EQ(pos, s.size());
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
constexpr bool is_correct_type = std::is_same_v<
|
||||||
|
decltype(convert_generator),
|
||||||
|
testing::internal::ParamConverterGenerator<
|
||||||
|
std::string, std::function<int64_t(std::string_view)>>>;
|
||||||
|
EXPECT_TRUE(is_correct_type);
|
||||||
|
const ParamGenerator<ConstructFromT<int8_t>> gen = convert_generator;
|
||||||
|
|
||||||
|
ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0),
|
||||||
|
ConstructFromT<int8_t>(1)};
|
||||||
|
VerifyGenerator(gen, expected_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ConvertTest, WithConverterFunctionPointer) {
|
||||||
|
int64_t (*func_ptr)(const std::string&) = [](const std::string& s) {
|
||||||
|
size_t pos;
|
||||||
|
int64_t value = std::stoll(s, &pos);
|
||||||
|
EXPECT_EQ(pos, s.size());
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
const ParamGenerator<ConstructFromT<int8_t>> gen =
|
||||||
|
ConvertGenerator(Values("0", std::string("1")), func_ptr);
|
||||||
|
|
||||||
|
ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0),
|
||||||
|
ConstructFromT<int8_t>(1)};
|
||||||
|
VerifyGenerator(gen, expected_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ConvertTest, WithConverterFunctionReference) {
|
||||||
|
int64_t (*func_ptr)(const std::string&) = [](const std::string& s) {
|
||||||
|
size_t pos;
|
||||||
|
int64_t value = std::stoll(s, &pos);
|
||||||
|
EXPECT_EQ(pos, s.size());
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
int64_t (&func_ref)(const std::string&) = *func_ptr;
|
||||||
|
const ParamGenerator<ConstructFromT<int8_t>> gen =
|
||||||
|
ConvertGenerator(Values("0", std::string("1")), func_ref);
|
||||||
|
|
||||||
|
ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0),
|
||||||
|
ConstructFromT<int8_t>(1)};
|
||||||
|
VerifyGenerator(gen, expected_values);
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that an generator produces correct sequence after being
|
// Tests that an generator produces correct sequence after being
|
||||||
// assigned from another generator.
|
// assigned from another generator.
|
||||||
TEST(ParamGeneratorTest, AssignmentWorks) {
|
TEST(ParamGeneratorTest, AssignmentWorks) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user