diff options
author | kosak@google.com <kosak@google.com@861a406c-534a-0410-8894-cb66d6ee9925> | 2015-07-24 19:46:18 +0000 |
---|---|---|
committer | kosak@google.com <kosak@google.com@861a406c-534a-0410-8894-cb66d6ee9925> | 2015-07-24 19:46:18 +0000 |
commit | 702663c6254347231c9a425e5fb1fe67ad0ffe58 (patch) | |
tree | 4034db2b543b36945b46702b0158168ef367d622 /include | |
parent | b7be629c0b272ff2b12d560ac3c92bcd9845106d (diff) | |
download | googletest-702663c6254347231c9a425e5fb1fe67ad0ffe58.tar.gz |
Add support for named value-parameterized tests.
git-svn-id: http://googletest.googlecode.com/svn/trunk@735 861a406c-534a-0410-8894-cb66d6ee9925
Diffstat (limited to 'include')
-rw-r--r-- | include/gtest/gtest-param-test.h | 20 | ||||
-rw-r--r-- | include/gtest/gtest-param-test.h.pump | 20 | ||||
-rw-r--r-- | include/gtest/internal/gtest-param-util.h | 131 |
3 files changed, 158 insertions, 13 deletions
diff --git a/include/gtest/gtest-param-test.h b/include/gtest/gtest-param-test.h index 9a1d8a6..038f9ba 100644 --- a/include/gtest/gtest-param-test.h +++ b/include/gtest/gtest-param-test.h @@ -1406,9 +1406,26 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3, GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ +// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user +// to specify a function or functor that generates custom test name suffixes +// based on the test parameters. The function should accept one argument of +// type testing::TestParamInfo<class ParamType>, and return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). It does not work +// for std::string or C strings. +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ ::testing::internal::ParamGenerator<test_case_name::ParamType> \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \ + return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \ + (__VA_ARGS__)(info); \ + } \ int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder<test_case_name>(\ @@ -1417,6 +1434,7 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3, __FILE__, __LINE__))->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ + >est_##prefix##test_case_name##_EvalGenerateName_, \ __FILE__, __LINE__) } // namespace testing diff --git a/include/gtest/gtest-param-test.h.pump b/include/gtest/gtest-param-test.h.pump index 4589650..3078d6d 100644 --- a/include/gtest/gtest-param-test.h.pump +++ b/include/gtest/gtest-param-test.h.pump @@ -472,9 +472,26 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ +// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user +// to specify a function or functor that generates custom test name suffixes +// based on the test parameters. The function should accept one argument of +// type testing::TestParamInfo<class ParamType>, and return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ ::testing::internal::ParamGenerator<test_case_name::ParamType> \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \ + return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \ + (__VA_ARGS__)(info); \ + } \ int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder<test_case_name>(\ @@ -483,6 +500,7 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( __FILE__, __LINE__))->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ + >est_##prefix##test_case_name##_EvalGenerateName_, \ __FILE__, __LINE__) } // namespace testing diff --git a/include/gtest/internal/gtest-param-util.h b/include/gtest/internal/gtest-param-util.h index efb2b94..5ffeaa4 100644 --- a/include/gtest/internal/gtest-param-util.h +++ b/include/gtest/internal/gtest-param-util.h @@ -34,7 +34,10 @@ #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#include <ctype.h> + #include <iterator> +#include <set> #include <utility> #include <vector> @@ -49,6 +52,27 @@ #if GTEST_HAS_PARAM_TEST namespace testing { + +// Input to a parameterized test name generator, describing a test parameter. +// Consists of the parameter value and the integer parameter index. +template <class ParamType> +struct TestParamInfo { + TestParamInfo(const ParamType& a_param, size_t an_index) : + param(a_param), + index(an_index) {} + ParamType param; + size_t index; +}; + +// A builtin parameterized test name generator which returns the result of +// testing::PrintToString. +struct PrintToStringParamName { + template <class ParamType> + std::string operator()(const TestParamInfo<ParamType>& info) const { + return PrintToString(info.param); + } +}; + namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. @@ -347,6 +371,37 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // +// Default parameterized test name generator, returns a string containing the +// integer test parameter index. +template <class ParamType> +std::string DefaultParamName(const TestParamInfo<ParamType>& info) { + Message name_stream; + name_stream << info.index; + return name_stream.GetString(); +} + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Parameterized test name overload helpers, which help the +// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized +// test name generator and user param name generator. +template <class ParamType, class ParamNameGenFunctor> +ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) { + return func; +} + +template <class ParamType> +struct ParamNameGenFunc { + typedef std::string Type(const TestParamInfo<ParamType>&); +}; + +template <class ParamType> +typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() { + return DefaultParamName; +} + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// // Stores a parameter value and later creates tests parameterized with that // value. template <class TestClass> @@ -449,6 +504,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { typedef typename TestCase::ParamType ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator<ParamType>(GeneratorCreationFunc)(); + typedef typename ParamNameGenFunc<ParamType>::Type ParamNameGeneratorFunc; explicit ParameterizedTestCaseInfo( const char* name, CodeLocation code_location) @@ -475,9 +531,11 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { // about a generator. int AddTestCaseInstantiation(const string& instantiation_name, GeneratorCreationFunc* func, - const char* /* file */, - int /* line */) { - instantiations_.push_back(::std::make_pair(instantiation_name, func)); + ParamNameGeneratorFunc* name_func, + const char* file, + int line) { + instantiations_.push_back( + InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test case @@ -492,20 +550,39 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { - const string& instantiation_name = gen_it->first; - ParamGenerator<ParamType> generator((*gen_it->second)()); + const string& instantiation_name = gen_it->name; + ParamGenerator<ParamType> generator((*gen_it->generator)()); + ParamNameGeneratorFunc* name_func = gen_it->name_func; + const char* file = gen_it->file; + int line = gen_it->line; string test_case_name; if ( !instantiation_name.empty() ) test_case_name = instantiation_name + "/"; test_case_name += test_info->test_case_base_name; - int i = 0; + size_t i = 0; + std::set<std::string> test_param_names; for (typename ParamGenerator<ParamType>::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; - test_name_stream << test_info->test_base_name << "/" << i; + + std::string param_name = name_func( + TestParamInfo<ParamType>(*param_it, i)); + + GTEST_CHECK_(IsValidParamName(param_name)) + << "Parameterized test name '" << param_name + << "' is invalid, in " << file + << " line " << line << std::endl; + + GTEST_CHECK_(test_param_names.count(param_name) == 0) + << "Duplicate parameterized test name '" << param_name + << "', in " << file << " line " << line << std::endl; + + test_param_names.insert(param_name); + + test_name_stream << test_info->test_base_name << "/" << param_name; MakeAndRegisterTestInfo( test_case_name.c_str(), test_name_stream.GetString().c_str(), @@ -537,10 +614,42 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory; }; typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer; - // Keeps pairs of <Instantiation name, Sequence generator creation function> - // received from INSTANTIATE_TEST_CASE_P macros. - typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> > - InstantiationContainer; + // Records data received from INSTANTIATE_TEST_CASE_P macros: + // <Instantiation name, Sequence generator creation function, + // Name generator function, Source file, Source line> + struct InstantiationInfo { + InstantiationInfo(const std::string &name_in, + GeneratorCreationFunc* generator_in, + ParamNameGeneratorFunc* name_func_in, + const char* file_in, + int line_in) + : name(name_in), + generator(generator_in), + name_func(name_func_in), + file(file_in), + line(line_in) {} + + std::string name; + GeneratorCreationFunc* generator; + ParamNameGeneratorFunc* name_func; + const char* file; + int line; + }; + typedef ::std::vector<InstantiationInfo> InstantiationContainer; + + static bool IsValidParamName(const std::string& name) { + // Check for empty string + if (name.empty()) + return false; + + // Check for invalid characters + for (std::string::size_type index = 0; index < name.size(); ++index) { + if (!isalnum(name[index]) && name[index] != '_') + return false; + } + + return true; + } const string test_case_name_; CodeLocation code_location_; |