Add support for named value-parameterized tests.

pull/496/merge
kosak 10 years ago
parent 41b5b28d48
commit 794ef030eb
  1. 20
      include/gtest/gtest-param-test.h
  2. 20
      include/gtest/gtest-param-test.h.pump
  3. 131
      include/gtest/internal/gtest-param-util.h
  4. 151
      test/gtest-param-test_test.cc
  5. 26
      test/gtest_output_test_.cc
  6. 21
      test/gtest_output_test_golden_lin.txt

@ -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, \
&gtest_##prefix##test_case_name##_EvalGenerator_, \
&gtest_##prefix##test_case_name##_EvalGenerateName_, \
__FILE__, __LINE__)
} // namespace testing

@ -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, \
&gtest_##prefix##test_case_name##_EvalGenerator_, \
&gtest_##prefix##test_case_name##_EvalGenerateName_, \
__FILE__, __LINE__)
} // namespace testing

@ -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.
@ -345,6 +369,37 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
const ContainerType container_;
}; // class ValuesInIteratorRangeGenerator
// 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
@ -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_;

@ -809,6 +809,157 @@ TEST_P(NamingTest, TestsReportCorrectNamesAndParameters) {
INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5));
// Tests that user supplied custom parameter names are working correctly.
// Runs the test with a builtin helper method which uses PrintToString,
// as well as a custom function and custom functor to ensure all possible
// uses work correctly.
class CustomFunctorNamingTest : public TestWithParam<std::string> {};
TEST_P(CustomFunctorNamingTest, CustomTestNames) {}
struct CustomParamNameFunctor {
std::string operator()(const ::testing::TestParamInfo<std::string>& info) {
return info.param;
}
};
INSTANTIATE_TEST_CASE_P(CustomParamNameFunctor,
CustomFunctorNamingTest,
Values(std::string("FunctorName")),
CustomParamNameFunctor());
INSTANTIATE_TEST_CASE_P(AllAllowedCharacters,
CustomFunctorNamingTest,
Values("abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"01234567890_"),
CustomParamNameFunctor());
inline std::string CustomParamNameFunction(
const ::testing::TestParamInfo<std::string>& info) {
return info.param;
}
class CustomFunctionNamingTest : public TestWithParam<std::string> {};
TEST_P(CustomFunctionNamingTest, CustomTestNames) {}
INSTANTIATE_TEST_CASE_P(CustomParamNameFunction,
CustomFunctionNamingTest,
Values(std::string("FunctionName")),
CustomParamNameFunction);
#if GTEST_LANG_CXX11
// Test custom naming with a lambda
class CustomLambdaNamingTest : public TestWithParam<std::string> {};
TEST_P(CustomLambdaNamingTest, CustomTestNames) {}
INSTANTIATE_TEST_CASE_P(CustomParamNameLambda,
CustomLambdaNamingTest,
Values(std::string("LambdaName")),
[](const ::testing::TestParamInfo<std::string>& info) {
return info.param;
});
#endif // GTEST_LANG_CXX11
TEST(CustomNamingTest, CheckNameRegistry) {
::testing::UnitTest* unit_test = ::testing::UnitTest::GetInstance();
std::set<std::string> test_names;
for (int case_num = 0;
case_num < unit_test->total_test_case_count();
++case_num) {
const ::testing::TestCase* test_case = unit_test->GetTestCase(case_num);
for (int test_num = 0;
test_num < test_case->total_test_count();
++test_num) {
const ::testing::TestInfo* test_info = test_case->GetTestInfo(test_num);
test_names.insert(std::string(test_info->name()));
}
}
EXPECT_EQ(1u, test_names.count("CustomTestNames/FunctorName"));
EXPECT_EQ(1u, test_names.count("CustomTestNames/FunctionName"));
#if GTEST_LANG_CXX11
EXPECT_EQ(1u, test_names.count("CustomTestNames/LambdaName"));
#endif // GTEST_LANG_CXX11
}
// Test a numeric name to ensure PrintToStringParamName works correctly.
class CustomIntegerNamingTest : public TestWithParam<int> {};
TEST_P(CustomIntegerNamingTest, TestsReportCorrectNames) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
Message test_name_stream;
test_name_stream << "TestsReportCorrectNames/" << GetParam();
EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name());
}
INSTANTIATE_TEST_CASE_P(PrintToString,
CustomIntegerNamingTest,
Range(0, 5),
::testing::PrintToStringParamName());
// Test a custom struct with PrintToString.
struct CustomStruct {
explicit CustomStruct(int value) : x(value) {}
int x;
};
std::ostream& operator<<(std::ostream& stream, const CustomStruct& val) {
stream << val.x;
return stream;
}
class CustomStructNamingTest : public TestWithParam<CustomStruct> {};
TEST_P(CustomStructNamingTest, TestsReportCorrectNames) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
Message test_name_stream;
test_name_stream << "TestsReportCorrectNames/" << GetParam();
EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name());
}
INSTANTIATE_TEST_CASE_P(PrintToString,
CustomStructNamingTest,
Values(CustomStruct(0), CustomStruct(1)),
::testing::PrintToStringParamName());
// Test that using a stateful parameter naming function works as expected.
struct StatefulNamingFunctor {
StatefulNamingFunctor() : sum(0) {}
std::string operator()(const ::testing::TestParamInfo<int>& info) {
int value = info.param + sum;
sum += info.param;
return ::testing::PrintToString(value);
}
int sum;
};
class StatefulNamingTest : public ::testing::TestWithParam<int> {
protected:
StatefulNamingTest() : sum_(0) {}
int sum_;
};
TEST_P(StatefulNamingTest, TestsReportCorrectNames) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
sum_ += GetParam();
Message test_name_stream;
test_name_stream << "TestsReportCorrectNames/" << sum_;
EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name());
}
INSTANTIATE_TEST_CASE_P(StatefulNamingFunctor,
StatefulNamingTest,
Range(0, 5),
StatefulNamingFunctor());
// Class that cannot be streamed into an ostream. It needs to be copyable
// (and, in case of MSVC, also assignable) in order to be a test parameter
// type. Its default copy constructor and assignment operator do exactly

@ -755,6 +755,32 @@ TEST(ExpectFatalFailureTest, FailsWhenStatementThrows) {
#endif // GTEST_HAS_EXCEPTIONS
// This #ifdef block tests the output of value-parameterized tests.
#if GTEST_HAS_PARAM_TEST
std::string ParamNameFunc(const testing::TestParamInfo<std::string>& info) {
return info.param;
}
class ParamTest : public testing::TestWithParam<std::string> {
};
TEST_P(ParamTest, Success) {
EXPECT_EQ("a", GetParam());
}
TEST_P(ParamTest, Failure) {
EXPECT_EQ("b", GetParam()) << "Expected failure";
}
INSTANTIATE_TEST_CASE_P(PrintingStrings,
ParamTest,
testing::Values(std::string("a")),
ParamNameFunc);
#endif // GTEST_HAS_PARAM_TEST
// This #ifdef block tests the output of typed tests.
#if GTEST_HAS_TYPED_TEST

@ -7,7 +7,7 @@ Expected: true
gtest_output_test_.cc:#: Failure
Value of: 3
Expected: 2
[==========] Running 64 tests from 28 test cases.
[==========] Running 66 tests from 29 test cases.
[----------] Global test environment set-up.
FooEnvironment::SetUp() called.
BarEnvironment::SetUp() called.
@ -601,6 +601,16 @@ Value of: GetParam()
Actual: 2
Expected: 1
[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
[----------] 2 tests from PrintingStrings/ParamTest
[ RUN ] PrintingStrings/ParamTest.Success/a
[ OK ] PrintingStrings/ParamTest.Success/a
[ RUN ] PrintingStrings/ParamTest.Failure/a
gtest_output_test_.cc:#: Failure
Value of: GetParam()
Actual: "a"
Expected: "b"
Expected failure
[ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a"
[----------] Global test environment tear-down
BarEnvironment::TearDown() called.
gtest_output_test_.cc:#: Failure
@ -610,9 +620,9 @@ FooEnvironment::TearDown() called.
gtest_output_test_.cc:#: Failure
Failed
Expected fatal failure.
[==========] 64 tests from 28 test cases ran.
[ PASSED ] 21 tests.
[ FAILED ] 43 tests, listed below:
[==========] 66 tests from 29 test cases ran.
[ PASSED ] 22 tests.
[ FAILED ] 44 tests, listed below:
[ FAILED ] NonfatalFailureTest.EscapesStringOperands
[ FAILED ] NonfatalFailureTest.DiffForLongStrings
[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
@ -656,8 +666,9 @@ Expected fatal failure.
[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure
[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
[ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a"
43 FAILED TESTS
44 FAILED TESTS
 YOU HAVE 1 DISABLED TEST
Note: Google Test filter = FatalFailureTest.*:LoggingTest.*

Loading…
Cancel
Save