mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 12:17:11 +01:00 
			
		
		
		
	Template tests: added TEMPLATE_PRODUCT_TEST_CASE
support for generating test cases based on multiple template template
types combined with template arguments for each of the template template
types specified
e.g.
```
TEMPLATE_PRODUCT_TEST_CASE("template product","[template]",
			   (std::tuple, std::pair, std::map),
			   ((int,float),(char,double),(int,char)))
```
will effectively create 9 test cases with types:
std::tuple<int,float>
std::tuple<char,double>
std::tuple<int,char>
std::pair<int,float>
std::pair<char, double>
std::pair<int,char>
std::map<int,float>
std::map<char,double>
std::map<int,char>
Tested type is accessible in test case body as TestType
Unique name is created by appending ` - <index>` to test name
since preprocessor has some limitations in recursions
Closes #1454
			
			
This commit is contained in:
		
							
								
								
									
										76
									
								
								include/internal/catch_meta.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								include/internal/catch_meta.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  *  Created by Jozef on 02/12/2018. | ||||
|  *  Copyright 2018 Two Blue Cubes Ltd. All rights reserved. | ||||
|  * | ||||
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
|  */ | ||||
|  | ||||
| #ifndef TWOBLUECUBES_CATCH_META_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_META_HPP_INCLUDED | ||||
|  | ||||
| template< typename... > | ||||
| struct TypeList{}; | ||||
|  | ||||
| template< typename... > | ||||
| struct append; | ||||
|  | ||||
| template< template<typename...> class L1 | ||||
| 	, typename...E1 | ||||
| 	, template<typename...> class L2 | ||||
| 	, typename...E2 | ||||
| 	> | ||||
| struct append< L1<E1...>, L2<E2...> > | ||||
| { | ||||
| 	using type = L1<E1..., E2...>; | ||||
| }; | ||||
|  | ||||
| template< template<typename...> class L1 | ||||
| 	, typename...E1 | ||||
| 	, template<typename...> class L2 | ||||
| 	, typename...E2 | ||||
| 	, typename...Rest | ||||
| 	> | ||||
| struct append< L1<E1...>, L2<E2...>, Rest...> | ||||
| { | ||||
| 	using type = typename append< L1<E1..., E2...>, Rest... >::type; | ||||
| }; | ||||
|  | ||||
| template< template<typename...> class | ||||
|         , typename... | ||||
|         > | ||||
| struct rewrap; | ||||
|  | ||||
| template< template<typename...> class Container | ||||
|         , template<typename...> class List | ||||
|         , typename...elems | ||||
|         > | ||||
| struct rewrap<Container, List<elems...>> | ||||
| { | ||||
|     using type = TypeList< Container< elems... > >; | ||||
| }; | ||||
|  | ||||
| template< template<typename...> class Container | ||||
|         , template<typename...> class List | ||||
|         , class...Elems | ||||
|         , typename...Elements> | ||||
| struct rewrap<Container, List<Elems...>, Elements...> | ||||
| { | ||||
|     using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type; | ||||
| }; | ||||
|  | ||||
| template< template<typename...> class...Containers > | ||||
| struct combine | ||||
| { | ||||
|     template< typename...Types > | ||||
|     struct with_types | ||||
|     { | ||||
|         template< template <typename...> class Final > | ||||
|         struct into | ||||
|         { | ||||
|             using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type; | ||||
|         }; | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_META_HPP_INCLUDED | ||||
| @@ -71,4 +71,9 @@ | ||||
| #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) | ||||
| #endif | ||||
|  | ||||
| #define INTERNAL_CATCH_MAKE_TYPE_LIST(types) TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)> | ||||
|  | ||||
| #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\ | ||||
|     CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types)) | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_PREPROCESSOR_HPP_INCLUDED | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #include "catch_stringref.h" | ||||
| #include "catch_type_traits.hpp" | ||||
| #include "catch_preprocessor.hpp" | ||||
| #include "catch_meta.hpp" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
| @@ -150,6 +151,38 @@ struct AutoReg : NonCopyable { | ||||
|             return 0;\ | ||||
|         }(); | ||||
|  | ||||
|     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \ | ||||
|         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS                      \ | ||||
|         template<typename TestType> static void TestFuncName();       \ | ||||
|         namespace {                                                   \ | ||||
|             template<typename... Types>                               \ | ||||
|             struct TestName {                                         \ | ||||
|                 TestName() {                                          \ | ||||
|                     CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)       \ | ||||
|                     int index = 0;                                    \ | ||||
|                     using expander = int[];                           \ | ||||
|                     (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \ | ||||
|                 }                                                     \ | ||||
|             };                                                        \ | ||||
|             static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ | ||||
|                 using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \ | ||||
|                             ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \ | ||||
|                 TestInit();                                           \ | ||||
|                 return 0;                                             \ | ||||
|             }();                                                      \ | ||||
|         }                                                             \ | ||||
|         CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS                    \ | ||||
|         template<typename TestType>                                   \ | ||||
|         static void TestFuncName() | ||||
|  | ||||
| #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | ||||
|     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ | ||||
|         INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__) | ||||
| #else | ||||
|     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ | ||||
|         INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) ) | ||||
| #endif | ||||
|  | ||||
|     #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \ | ||||
|         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | ||||
|         namespace{ \ | ||||
| @@ -180,4 +213,39 @@ struct AutoReg : NonCopyable { | ||||
|         INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) ) | ||||
| #endif | ||||
|  | ||||
|     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\ | ||||
|         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | ||||
|         template<typename TestType> \ | ||||
|             struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ | ||||
|                 void test();\ | ||||
|             };\ | ||||
|         namespace {\ | ||||
|             template<typename...Types>\ | ||||
|             struct TestNameClass{\ | ||||
|                 TestNameClass(){\ | ||||
|                     CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\ | ||||
|                     int index = 0;\ | ||||
|                     using expander = int[];\ | ||||
|                     (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \ | ||||
|                 }\ | ||||
|             };\ | ||||
|             static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ | ||||
|                 using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\ | ||||
|                             ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\ | ||||
|                 TestInit();\ | ||||
|                 return 0;\ | ||||
|             }(); \ | ||||
|         }\ | ||||
|         CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ | ||||
|         template<typename TestType> \ | ||||
|         void TestName<TestType>::test() | ||||
|  | ||||
| #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | ||||
|     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ | ||||
|         INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) | ||||
| #else | ||||
|     #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ | ||||
|         INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) ) | ||||
| #endif | ||||
|  | ||||
| #endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jozef Grajciar
					Jozef Grajciar