@@ -174,6 +174,7 @@ TEST_P(DerivedTest, DoesBlah) {
174174
175175#endif // 0
176176
177+ #include < functional>
177178#include < iterator>
178179#include < utility>
179180
@@ -413,7 +414,8 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
413414// Synopsis:
414415// ConvertGenerator<T>(gen)
415416// - returns a generator producing the same elements as generated by gen, but
416- // each element is static_cast to type T before being returned
417+ // each T-typed element is static_cast to a type deduced from the interface
418+ // that accepts this generator, and then returned
417419//
418420// It is useful when using the Combine() function to get the generated
419421// parameters in a custom type instead of std::tuple
@@ -441,10 +443,65 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
441443// Combine(Values("cat", "dog"),
442444// Values(BLACK, WHITE))));
443445//
444- template <typename T>
445- internal::ParamConverterGenerator<T> ConvertGenerator (
446- internal::ParamGenerator<T> gen) {
447- return internal::ParamConverterGenerator<T>(gen);
446+ template <typename RequestedT>
447+ internal::ParamConverterGenerator<RequestedT> ConvertGenerator (
448+ internal::ParamGenerator<RequestedT> gen) {
449+ return internal::ParamConverterGenerator<RequestedT>(std::move (gen));
450+ }
451+
452+ // As above, but takes a callable as a second argument. The callable converts
453+ // the generated parameter to the test fixture's parameter type. This allows you
454+ // to use a parameter type that does not have a converting constructor from the
455+ // generated type.
456+ //
457+ // Example:
458+ //
459+ // This will instantiate tests in test suite AnimalTest each one with
460+ // the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
461+ // tuple("dog", BLACK), and tuple("dog", WHITE):
462+ //
463+ // enum Color { BLACK, GRAY, WHITE };
464+ // struct ParamType {
465+ // std::string animal;
466+ // Color color;
467+ // };
468+ // class AnimalTest
469+ // : public testing::TestWithParam<ParamType> {...};
470+ //
471+ // TEST_P(AnimalTest, AnimalLooksNice) {...}
472+ //
473+ // INSTANTIATE_TEST_SUITE_P(
474+ // AnimalVariations, AnimalTest,
475+ // ConvertGenerator(Combine(Values("cat", "dog"), Values(BLACK, WHITE)),
476+ // [](std::tuple<std::string, Color> t) {
477+ // return ParamType{.animal = std::get<0>(t),
478+ // .color = std::get<1>(t)};
479+ // }));
480+ //
481+ template <typename T, int &... ExplicitArgumentBarrier, typename Gen,
482+ typename Func,
483+ typename StdFunction = decltype (std::function(std::declval<Func>()))>
484+ internal::ParamConverterGenerator<T, StdFunction> ConvertGenerator(Gen&& gen,
485+ Func&& f) {
486+ return internal::ParamConverterGenerator<T, StdFunction>(
487+ std::forward<Gen>(gen), std::forward<Func>(f));
488+ }
489+
490+ // As above, but infers the T from the supplied std::function instead of
491+ // having the caller specify it.
492+ template <int &... ExplicitArgumentBarrier, typename Gen, typename Func,
493+ typename StdFunction = decltype (std::function(std::declval<Func>()))>
494+ auto ConvertGenerator (Gen&& gen, Func&& f) {
495+ constexpr bool is_single_arg_std_function =
496+ internal::IsSingleArgStdFunction<StdFunction>::value;
497+ if constexpr (is_single_arg_std_function) {
498+ return ConvertGenerator<
499+ typename internal::FuncSingleParamType<StdFunction>::type>(
500+ std::forward<Gen>(gen), std::forward<Func>(f));
501+ } else {
502+ static_assert (is_single_arg_std_function,
503+ " The call signature must contain a single argument." );
504+ }
448505}
449506
450507#define TEST_P (test_suite_name, test_name ) \
@@ -469,7 +526,7 @@ internal::ParamConverterGenerator<T> ConvertGenerator(
469526 ::testing::internal::CodeLocation(__FILE__, __LINE__)); \
470527 return 0 ; \
471528 } \
472- GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static int gtest_registering_dummy_; \
529+ [[maybe_unused]] static int gtest_registering_dummy_; \
473530 }; \
474531 int GTEST_TEST_CLASS_NAME_ (test_suite_name, \
475532 test_name)::gtest_registering_dummy_ = \
@@ -493,39 +550,38 @@ internal::ParamConverterGenerator<T> ConvertGenerator(
493550#define GTEST_GET_FIRST_ (first, ...) first
494551#define GTEST_GET_SECOND_ (first, second, ...) second
495552
496- #define INSTANTIATE_TEST_SUITE_P (prefix, test_suite_name, ...) \
497- static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \
498- gtest_##prefix##test_suite_name##_EvalGenerator_() { \
499- return GTEST_EXPAND_ (GTEST_GET_FIRST_ (__VA_ARGS__, DUMMY_PARAM_)); \
500- } \
501- static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \
502- const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \
503- if (::testing::internal::AlwaysFalse ()) { \
504- ::testing::internal::TestNotEmpty (GTEST_EXPAND_(GTEST_GET_SECOND_( \
505- __VA_ARGS__, \
506- ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
507- DUMMY_PARAM_))); \
508- auto t = std::make_tuple (__VA_ARGS__); \
509- static_assert (std::tuple_size<decltype (t)>::value <= 2 , \
510- " Too Many Args!" ); \
511- } \
512- return ((GTEST_EXPAND_ (GTEST_GET_SECOND_ ( \
513- __VA_ARGS__, \
514- ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
515- DUMMY_PARAM_))))(info); \
516- } \
517- GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static int \
518- gtest_##prefix##test_suite_name##_dummy_ = \
519- ::testing::UnitTest::GetInstance () \
520- ->parameterized_test_registry() \
521- .GetTestSuitePatternHolder<test_suite_name>( \
522- GTEST_STRINGIFY_ (test_suite_name), \
523- ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
524- ->AddTestSuiteInstantiation( \
525- GTEST_STRINGIFY_ (prefix), \
526- >est_##prefix##test_suite_name##_EvalGenerator_, \
527- >est_##prefix##test_suite_name##_EvalGenerateName_, \
528- __FILE__, __LINE__)
553+ #define INSTANTIATE_TEST_SUITE_P (prefix, test_suite_name, ...) \
554+ static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \
555+ gtest_##prefix##test_suite_name##_EvalGenerator_() { \
556+ return GTEST_EXPAND_ (GTEST_GET_FIRST_ (__VA_ARGS__, DUMMY_PARAM_)); \
557+ } \
558+ static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \
559+ const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \
560+ if (::testing::internal::AlwaysFalse ()) { \
561+ ::testing::internal::TestNotEmpty (GTEST_EXPAND_(GTEST_GET_SECOND_( \
562+ __VA_ARGS__, \
563+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
564+ DUMMY_PARAM_))); \
565+ auto t = std::make_tuple (__VA_ARGS__); \
566+ static_assert (std::tuple_size<decltype (t)>::value <= 2 , \
567+ " Too Many Args!" ); \
568+ } \
569+ return ((GTEST_EXPAND_ (GTEST_GET_SECOND_ ( \
570+ __VA_ARGS__, \
571+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
572+ DUMMY_PARAM_))))(info); \
573+ } \
574+ [[maybe_unused]] static int gtest_##prefix##test_suite_name##_dummy_ = \
575+ ::testing::UnitTest::GetInstance () \
576+ ->parameterized_test_registry() \
577+ .GetTestSuitePatternHolder<test_suite_name>( \
578+ GTEST_STRINGIFY_ (test_suite_name), \
579+ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
580+ ->AddTestSuiteInstantiation( \
581+ GTEST_STRINGIFY_ (prefix), \
582+ >est_##prefix##test_suite_name##_EvalGenerator_, \
583+ >est_##prefix##test_suite_name##_EvalGenerateName_, __FILE__, \
584+ __LINE__)
529585
530586// Allow Marking a Parameterized test class as not needing to be instantiated.
531587#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST (T ) \
0 commit comments