Commit 03867b53 authored by Abseil Team's avatar Abseil Team Committed by Gennadiy Civil
Browse files

Googletest export

Add the possibility of specifying the name in type parameterized tests.

Similar to how the last parameter of INSTANTIATE_TEST_CASE_P allows to override the name for (non-type) parametrized tests, this adds the possibility of adding a parameter to INSTANTIATE_TYPED_TEST_CASE_P. The argument has to be a class, which contains a static templated function GetName<T>(int), returning the name for type T.

PiperOrigin-RevId: 210532231
parent 52f8183e
......@@ -83,6 +83,24 @@ TYPED_TEST(FooTest, DoesBlah) {
TYPED_TEST(FooTest, HasPropertyA) { ... }
// TYPED_TEST_CASE takes an optional third argument which allows to specify a
// class that generates custom test name suffixes based on the type. This should
// be a class which has a static template function GetName(int index) returning
// a string for each type. The provided integer index equals the index of the
// type in the provided type list. In many cases the index can be ignored.
//
// For example:
// class MyTypeNames {
// public:
// template <typename T>
// static std::string GetName(int) {
// if (std::is_same<T, char>()) return "char";
// if (std::is_same<T, int>()) return "int";
// if (std::is_same<T, unsigned int>()) return "unsigned_int";
// }
// };
// TYPED_TEST_CASE(FooTest, MyTypes, MyTypeNames);
#endif // 0
// Type-parameterized tests are abstract test patterns parameterized
......@@ -144,6 +162,11 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
// If the type list contains only one type, you can write that type
// directly without Types<...>:
// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
//
// Similar to the optional argument of TYPED_TEST_CASE above,
// INSTANTIATE_TEST_CASE_P takes an optional fourth argument which allows to
// generate custom names.
// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes, MyTypeNames);
#endif // 0
......@@ -160,32 +183,45 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
// given test case.
# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
// Expands to the name of the typedef for the NameGenerator, responsible for
// creating the suffixes of the name.
#define GTEST_NAME_GENERATOR_(TestCaseName) \
gtest_type_params_##TestCaseName##_NameGenerator
// The 'Types' template argument below must have spaces around it
// since some compilers may choke on '>>' when passing a template
// instance (e.g. Types<int>)
# define TYPED_TEST_CASE(CaseName, Types) \
typedef ::testing::internal::TypeList< Types >::type \
GTEST_TYPE_PARAMS_(CaseName)
# define TYPED_TEST(CaseName, TestName) \
template <typename gtest_TypeParam_> \
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
: public CaseName<gtest_TypeParam_> { \
private: \
typedef CaseName<gtest_TypeParam_> TestFixture; \
typedef gtest_TypeParam_ TypeParam; \
virtual void TestBody(); \
}; \
bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
::testing::internal::TypeParameterizedTest< \
CaseName, \
::testing::internal::TemplateSel< \
GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
GTEST_TYPE_PARAMS_(CaseName)>::Register(\
"", ::testing::internal::CodeLocation(__FILE__, __LINE__), \
#CaseName, #TestName, 0); \
template <typename gtest_TypeParam_> \
void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
# define TYPED_TEST_CASE(CaseName, Types, ...) \
typedef ::testing::internal::TypeList< Types >::type GTEST_TYPE_PARAMS_( \
CaseName); \
typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
GTEST_NAME_GENERATOR_(CaseName)
# define TYPED_TEST(CaseName, TestName) \
template <typename gtest_TypeParam_> \
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
: public CaseName<gtest_TypeParam_> { \
private: \
typedef CaseName<gtest_TypeParam_> TestFixture; \
typedef gtest_TypeParam_ TypeParam; \
virtual void TestBody(); \
}; \
bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
::testing::internal::TypeParameterizedTest< \
CaseName, \
::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName, \
TestName)>, \
GTEST_TYPE_PARAMS_( \
CaseName)>::Register("", \
::testing::internal::CodeLocation( \
__FILE__, __LINE__), \
#CaseName, #TestName, 0, \
::testing::internal::GenerateNames< \
GTEST_NAME_GENERATOR_(CaseName), \
GTEST_TYPE_PARAMS_(CaseName)>()); \
template <typename gtest_TypeParam_> \
void GTEST_TEST_CLASS_NAME_(CaseName, \
TestName)<gtest_TypeParam_>::TestBody()
#endif // GTEST_HAS_TYPED_TEST
......@@ -250,15 +286,19 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
// The 'Types' template argument below must have spaces around it
// since some compilers may choke on '>>' when passing a template
// instance (e.g. Types<int>)
# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
::testing::internal::TypeParameterizedTestCase<CaseName, \
GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
::testing::internal::TypeList< Types >::type>::Register(\
#Prefix, \
::testing::internal::CodeLocation(__FILE__, __LINE__), \
&GTEST_TYPED_TEST_CASE_P_STATE_(CaseName), \
#CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types, ...) \
bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
::testing::internal::TypeParameterizedTestCase< \
CaseName, GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
::testing::internal::TypeList< Types >::type>:: \
Register(#Prefix, \
::testing::internal::CodeLocation(__FILE__, __LINE__), \
&GTEST_TYPED_TEST_CASE_P_STATE_(CaseName), #CaseName, \
GTEST_REGISTERED_TEST_NAMES_(CaseName), \
::testing::internal::GenerateNames< \
::testing::internal::NameGeneratorSelector< \
__VA_ARGS__>::type, \
::testing::internal::TypeList< Types >::type>())
#endif // GTEST_HAS_TYPED_TEST_P
......
......@@ -606,6 +606,37 @@ inline std::string GetPrefixUntilComma(const char* str) {
void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest);
// The default argument to the template below for the case when the user does
// not provide a name generator.
struct DefaultNameGenerator {
template <typename T>
static std::string GetName(int i) {
return StreamableToString(i);
}
};
template <typename Provided = DefaultNameGenerator>
struct NameGeneratorSelector {
typedef Provided type;
};
template <typename NameGenerator>
void GenerateNamesRecursively(Types0, std::vector<std::string>*, int) {}
template <typename NameGenerator, typename Types>
void GenerateNamesRecursively(Types, std::vector<std::string>* result, int i) {
result->push_back(NameGenerator::template GetName<typename Types::Head>(i));
GenerateNamesRecursively<NameGenerator>(typename Types::Tail(), result,
i + 1);
}
template <typename NameGenerator, typename Types>
std::vector<std::string> GenerateNames() {
std::vector<std::string> result;
GenerateNamesRecursively<NameGenerator>(Types(), &result, 0);
return result;
}
// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
// registers a list of type-parameterized tests with Google Test. The
// return value is insignificant - we just need to return something
......@@ -620,10 +651,10 @@ class TypeParameterizedTest {
// specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
// Types). Valid values for 'index' are [0, N - 1] where N is the
// length of Types.
static bool Register(const char* prefix,
const CodeLocation& code_location,
const char* case_name, const char* test_names,
int index) {
static bool Register(const char* prefix, const CodeLocation& code_location,
const char* case_name, const char* test_names, int index,
const std::vector<std::string>& type_names =
GenerateNames<DefaultNameGenerator, Types>()) {
typedef typename Types::Head Type;
typedef Fixture<Type> FixtureClass;
typedef typename GTEST_BIND_(TestSel, Type) TestClass;
......@@ -631,20 +662,23 @@ class TypeParameterizedTest {
// First, registers the first type-parameterized test in the type
// list.
MakeAndRegisterTestInfo(
(std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
+ StreamableToString(index)).c_str(),
(std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name +
"/" + type_names[index])
.c_str(),
StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
GetTypeName<Type>().c_str(),
NULL, // No value parameter.
code_location,
GetTypeId<FixtureClass>(),
TestClass::SetUpTestCase,
TestClass::TearDownTestCase,
new TestFactoryImpl<TestClass>);
code_location, GetTypeId<FixtureClass>(), TestClass::SetUpTestCase,
TestClass::TearDownTestCase, new TestFactoryImpl<TestClass>);
// Next, recurses (at compile time) with the tail of the type list.
return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
::Register(prefix, code_location, case_name, test_names, index + 1);
return TypeParameterizedTest<Fixture, TestSel,
typename Types::Tail>::Register(prefix,
code_location,
case_name,
test_names,
index + 1,
type_names);
}
};
......@@ -654,7 +688,9 @@ class TypeParameterizedTest<Fixture, TestSel, Types0> {
public:
static bool Register(const char* /*prefix*/, const CodeLocation&,
const char* /*case_name*/, const char* /*test_names*/,
int /*index*/) {
int /*index*/,
const std::vector<std::string>& =
std::vector<std::string>() /*type_names*/) {
return true;
}
};
......@@ -667,8 +703,10 @@ template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
class TypeParameterizedTestCase {
public:
static bool Register(const char* prefix, CodeLocation code_location,
const TypedTestCasePState* state,
const char* case_name, const char* test_names) {
const TypedTestCasePState* state, const char* case_name,
const char* test_names,
const std::vector<std::string>& type_names =
GenerateNames<DefaultNameGenerator, Types>()) {
std::string test_name = StripTrailingSpaces(
GetPrefixUntilComma(test_names));
if (!state->TestExists(test_name)) {
......@@ -685,12 +723,14 @@ class TypeParameterizedTestCase {
// First, register the first test in 'Test' for each type in 'Types'.
TypeParameterizedTest<Fixture, Head, Types>::Register(
prefix, test_location, case_name, test_names, 0);
prefix, test_location, case_name, test_names, 0, type_names);
// Next, recurses (at compile time) with the tail of the test list.
return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
::Register(prefix, code_location, state,
case_name, SkipComma(test_names));
return TypeParameterizedTestCase<Fixture, typename Tests::Tail,
Types>::Register(prefix, code_location,
state, case_name,
SkipComma(test_names),
type_names);
}
};
......@@ -700,7 +740,9 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> {
public:
static bool Register(const char* /*prefix*/, const CodeLocation&,
const TypedTestCasePState* /*state*/,
const char* /*case_name*/, const char* /*test_names*/) {
const char* /*case_name*/, const char* /*test_names*/,
const std::vector<std::string>& =
std::vector<std::string>() /*type_names*/) {
return true;
}
};
......
......@@ -801,6 +801,28 @@ TYPED_TEST(TypedTest, Failure) {
EXPECT_EQ(1, TypeParam()) << "Expected failure";
}
typedef testing::Types<char, int> TypesForTestWithNames;
template <typename T>
class TypedTestWithNames : public testing::Test {};
class TypedTestNames {
public:
template <typename T>
static std::string GetName(int i) {
if (testing::internal::IsSame<T, char>::value)
return std::string("char_") + ::testing::PrintToString(i);
if (testing::internal::IsSame<T, int>::value)
return std::string("int_") + ::testing::PrintToString(i);
}
};
TYPED_TEST_CASE(TypedTestWithNames, TypesForTestWithNames, TypedTestNames);
TYPED_TEST(TypedTestWithNames, Success) {}
TYPED_TEST(TypedTestWithNames, Failure) { FAIL(); }
#endif // GTEST_HAS_TYPED_TEST
// This #ifdef block tests the output of type-parameterized tests.
......@@ -825,6 +847,22 @@ REGISTER_TYPED_TEST_CASE_P(TypedTestP, Success, Failure);
typedef testing::Types<unsigned char, unsigned int> UnsignedTypes;
INSTANTIATE_TYPED_TEST_CASE_P(Unsigned, TypedTestP, UnsignedTypes);
class TypedTestPNames {
public:
template <typename T>
static std::string GetName(int i) {
if (testing::internal::IsSame<T, unsigned char>::value) {
return std::string("unsigned_char_") + ::testing::PrintToString(i);
}
if (testing::internal::IsSame<T, unsigned int>::value) {
return std::string("unsigned_int_") + ::testing::PrintToString(i);
}
}
};
INSTANTIATE_TYPED_TEST_CASE_P(UnsignedCustomName, TypedTestP, UnsignedTypes,
TypedTestPNames);
#endif // GTEST_HAS_TYPED_TEST_P
#if GTEST_HAS_DEATH_TEST
......
......@@ -165,6 +165,40 @@ TYPED_TEST(NumericTest, DefaultIsZero) {
} // namespace library1
// Tests that custom names work.
template <typename T>
class TypedTestWithNames : public Test {};
class TypedTestNames {
public:
template <typename T>
static std::string GetName(int i) {
if (testing::internal::IsSame<T, char>::value) {
return std::string("char_") + ::testing::PrintToString(i);
}
if (testing::internal::IsSame<T, int>::value) {
return std::string("int_") + ::testing::PrintToString(i);
}
}
};
TYPED_TEST_CASE(TypedTestWithNames, TwoTypes, TypedTestNames);
TYPED_TEST(TypedTestWithNames, TestCaseName) {
if (testing::internal::IsSame<TypeParam, char>::value) {
EXPECT_STREQ(::testing::UnitTest::GetInstance()
->current_test_info()
->test_case_name(),
"TypedTestWithNames/char_0");
}
if (testing::internal::IsSame<TypeParam, int>::value) {
EXPECT_STREQ(::testing::UnitTest::GetInstance()
->current_test_info()
->test_case_name(),
"TypedTestWithNames/int_1");
}
}
#endif // GTEST_HAS_TYPED_TEST
// This #ifdef block tests type-parameterized tests.
......@@ -265,6 +299,46 @@ REGISTER_TYPED_TEST_CASE_P(DerivedTest,
typedef Types<short, long> MyTwoTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, DerivedTest, MyTwoTypes);
// Tests that custom names work with type parametrized tests. We reuse the
// TwoTypes from above here.
template <typename T>
class TypeParametrizedTestWithNames : public Test {};
TYPED_TEST_CASE_P(TypeParametrizedTestWithNames);
TYPED_TEST_P(TypeParametrizedTestWithNames, TestCaseName) {
if (testing::internal::IsSame<TypeParam, char>::value) {
EXPECT_STREQ(::testing::UnitTest::GetInstance()
->current_test_info()
->test_case_name(),
"CustomName/TypeParametrizedTestWithNames/p_char_0");
}
if (testing::internal::IsSame<TypeParam, int>::value) {
EXPECT_STREQ(::testing::UnitTest::GetInstance()
->current_test_info()
->test_case_name(),
"CustomName/TypeParametrizedTestWithNames/p_int_1");
}
}
REGISTER_TYPED_TEST_CASE_P(TypeParametrizedTestWithNames, TestCaseName);
class TypeParametrizedTestNames {
public:
template <typename T>
static std::string GetName(int i) {
if (testing::internal::IsSame<T, char>::value) {
return std::string("p_char_") + ::testing::PrintToString(i);
}
if (testing::internal::IsSame<T, int>::value) {
return std::string("p_int_") + ::testing::PrintToString(i);
}
}
};
INSTANTIATE_TYPED_TEST_CASE_P(CustomName, TypeParametrizedTestWithNames,
TwoTypes, TypeParametrizedTestNames);
// Tests that multiple TYPED_TEST_CASE_P's can be defined in the same
// translation unit.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment