aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorshiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925>2008-09-08 17:55:52 +0000
committershiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925>2008-09-08 17:55:52 +0000
commita2b1a8556ea64014606d78b09333d9c522430a25 (patch)
treea4f4a88d89b4f957655a479bba3f33908572fcb5 /include
parent0c5a66245b8c5939b36b2aad6f4d5ab89b724b1a (diff)
downloadgoogletest-a2b1a8556ea64014606d78b09333d9c522430a25.tar.gz
googletest-a2b1a8556ea64014606d78b09333d9c522430a25.tar.bz2
googletest-a2b1a8556ea64014606d78b09333d9c522430a25.zip
Adds support for type-parameterized tests (by Zhanyong Wan); also adds case-insensitive wide string comparison to the String class (by Vlad Losev).
Diffstat (limited to 'include')
-rw-r--r--include/gtest/gtest.h83
-rw-r--r--include/gtest/internal/gtest-internal.h207
-rw-r--r--include/gtest/internal/gtest-port.h14
-rw-r--r--include/gtest/internal/gtest-string.h19
4 files changed, 266 insertions, 57 deletions
diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h
index 1f5d7640..37ea6b04 100644
--- a/include/gtest/gtest.h
+++ b/include/gtest/gtest.h
@@ -62,11 +62,13 @@
// Windows proper with Visual C++ and MS C library (_MSC_VER && !_WIN32_WCE) and
// Windows Mobile with Visual C++ and no C library (_WIN32_WCE).
+#include <limits>
#include <gtest/internal/gtest-internal.h>
#include <gtest/internal/gtest-string.h>
#include <gtest/gtest-death-test.h>
#include <gtest/gtest-message.h>
#include <gtest/gtest_prod.h>
+#include <gtest/gtest-typed-test.h>
// Depending on the platform, different string classes are available.
// On Windows, ::std::string compiles only when exceptions are
@@ -217,12 +219,28 @@ class Test {
// Defines types for pointers to functions that set up and tear down
// a test case.
- typedef void (*SetUpTestCaseFunc)();
- typedef void (*TearDownTestCaseFunc)();
+ typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+ typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
// The d'tor is virtual as we intend to inherit from Test.
virtual ~Test();
+ // Sets up the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::SetUpTestCase() before running the first
+ // test in test case Foo. Hence a sub-class can define its own
+ // SetUpTestCase() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestCase() {}
+
+ // Tears down the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::TearDownTestCase() after running the last
+ // test in test case Foo. Hence a sub-class can define its own
+ // TearDownTestCase() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestCase() {}
+
// Returns true iff the current test has a fatal failure.
static bool HasFatalFailure();
@@ -245,22 +263,6 @@ class Test {
// Creates a Test object.
Test();
- // Sets up the stuff shared by all tests in this test case.
- //
- // Google Test will call Foo::SetUpTestCase() before running the first
- // test in test case Foo. Hence a sub-class can define its own
- // SetUpTestCase() method to shadow the one defined in the super
- // class.
- static void SetUpTestCase() {}
-
- // Tears down the stuff shared by all tests in this test case.
- //
- // Google Test will call Foo::TearDownTestCase() after running the last
- // test in test case Foo. Hence a sub-class can define its own
- // TearDownTestCase() method to shadow the one defined in the super
- // class.
- static void TearDownTestCase() {}
-
// Sets up the test fixture.
virtual void SetUp();
@@ -327,36 +329,18 @@ class TestInfo {
// don't inherit from TestInfo.
~TestInfo();
- // Creates a TestInfo object and registers it with the UnitTest
- // singleton; returns the created object.
- //
- // Arguments:
- //
- // test_case_name: name of the test case
- // name: name of the test
- // fixture_class_id: ID of the test fixture class
- // set_up_tc: pointer to the function that sets up the test case
- // tear_down_tc: pointer to the function that tears down the test case
- // factory: Pointer to the factory that creates a test object.
- // The newly created TestInfo instance will assume
- // ownershi pof the factory object.
- //
- // This is public only because it's needed by the TEST and TEST_F macros.
- // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
- static TestInfo* MakeAndRegisterInstance(
- const char* test_case_name,
- const char* name,
- internal::TypeId fixture_class_id,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc,
- internal::TestFactoryBase* factory);
-
// Returns the test case name.
const char* test_case_name() const;
// Returns the test name.
const char* name() const;
+ // Returns the test case comment.
+ const char* test_case_comment() const;
+
+ // Returns the test comment.
+ const char* comment() const;
+
// Returns true if this test should run.
//
// Google Test allows the user to filter the tests by their full names.
@@ -383,6 +367,13 @@ class TestInfo {
friend class internal::UnitTestImpl;
friend class Test;
friend class TestCase;
+ friend TestInfo* internal::MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ internal::TypeId fixture_class_id,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ internal::TestFactoryBase* factory);
// Increments the number of death tests encountered in this test so
// far.
@@ -395,6 +386,7 @@ class TestInfo {
// Constructs a TestInfo object. The newly constructed instance assumes
// ownership of the factory object.
TestInfo(const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
internal::TypeId fixture_class_id,
internal::TestFactoryBase* factory);
@@ -1118,9 +1110,10 @@ AssertionResult DoubleLE(const char* expr1, const char* expr2,
//
// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
//
-// When expr unexpectedly fails or succeeds, Google Test prints the expected result
-// and the actual result with both a human-readable string representation of
-// the error, if available, as well as the hex result code.
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
#define EXPECT_HRESULT_SUCCEEDED(expr) \
EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h
index dc6154b6..8adf13e4 100644
--- a/include/gtest/internal/gtest-internal.h
+++ b/include/gtest/internal/gtest-internal.h
@@ -46,11 +46,15 @@
#include <unistd.h>
#endif // GTEST_OS_LINUX
-#include <iomanip> // NOLINT
-#include <limits> // NOLINT
+#include <ctype.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
#include <gtest/internal/gtest-string.h>
#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-type-util.h>
// Due to C++ preprocessor weirdness, we need double indirection to
// concatenate two tokens when one of them is __LINE__. Writing
@@ -521,6 +525,182 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT
#endif // GTEST_OS_WINDOWS
+// Formats a source file path and a line number as they would appear
+// in a compiler error message.
+inline String FormatFileLocation(const char* file, int line) {
+ const char* const file_name = file == NULL ? "unknown file" : file;
+ if (line < 0) {
+ return String::Format("%s:", file_name);
+ }
+#ifdef _MSC_VER
+ return String::Format("%s(%d):", file_name, line);
+#else
+ return String::Format("%s:%d:", file_name, line);
+#endif // _MSC_VER
+}
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// test_case_comment: a comment on the test case that will be included in
+// the test output
+// comment: a comment on the test that will be included in the
+// test output
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory);
+
+#if defined(GTEST_HAS_TYPED_TEST) || defined(GTEST_HAS_TYPED_TEST_P)
+
+// State of the definition of a type-parameterized test case.
+class TypedTestCasePState {
+ public:
+ TypedTestCasePState() : registered_(false) {}
+
+ // Adds the given test name to defined_test_names_ and return true
+ // if the test case hasn't been registered; otherwise aborts the
+ // program.
+ bool AddTestName(const char* file, int line, const char* case_name,
+ const char* test_name) {
+ if (registered_) {
+ fprintf(stderr, "%s Test %s must be defined before "
+ "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+ FormatFileLocation(file, line).c_str(), test_name, case_name);
+ abort();
+ }
+ defined_test_names_.insert(test_name);
+ return true;
+ }
+
+ // Verifies that registered_tests match the test names in
+ // defined_test_names_; returns registered_tests if successful, or
+ // aborts the program otherwise.
+ const char* VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests);
+
+ private:
+ bool registered_;
+ ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ if (comma == NULL) {
+ return NULL;
+ }
+ while (isspace(*(++comma))) {}
+ return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline String GetPrefixUntilComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ return comma == NULL ? String(str) : String(str, comma - str);
+}
+
+// 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
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter. It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+ // 'index' is the index of the test in the type list 'Types'
+ // 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 char* case_name,
+ const char* test_names, int index) {
+ typedef typename Types::Head Type;
+ typedef Fixture<Type> FixtureClass;
+ typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+ // First, registers the first type-parameterized test in the type
+ // list.
+ MakeAndRegisterTestInfo(
+ String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",
+ case_name, index).c_str(),
+ GetPrefixUntilComma(test_names).c_str(),
+ String::Format("TypeParam = %s", GetTypeName<Type>().c_str()).c_str(),
+ "",
+ 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, case_name, test_names, index + 1);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0> {
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/, int /*index*/) {
+ return true;
+ }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test. The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase {
+ public:
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names) {
+ typedef typename Tests::Head Head;
+
+ // First, register the first test in 'Test' for each type in 'Types'.
+ TypeParameterizedTest<Fixture, Head, Types>::Register(
+ prefix, case_name, test_names, 0);
+
+ // Next, recurses (at compile time) with the tail of the test list.
+ return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+ ::Register(prefix, case_name, SkipComma(test_names));
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+ public:
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names) {
+ return true;
+ }
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
} // namespace internal
} // namespace testing
@@ -544,27 +724,32 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT
else \
fail("Value of: " booltext "\n Actual: " #actual "\nExpected: " #expected)
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ test_case_name##_##test_name##_Test
+
// Helper macro for defining tests.
#define GTEST_TEST(test_case_name, test_name, parent_class)\
-class test_case_name##_##test_name##_Test : public parent_class {\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
public:\
- test_case_name##_##test_name##_Test() {}\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
private:\
virtual void TestBody();\
static ::testing::TestInfo* const test_info_;\
- GTEST_DISALLOW_COPY_AND_ASSIGN(test_case_name##_##test_name##_Test);\
+ GTEST_DISALLOW_COPY_AND_ASSIGN(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
};\
\
-::testing::TestInfo* const test_case_name##_##test_name##_Test::test_info_ =\
- ::testing::TestInfo::MakeAndRegisterInstance(\
- #test_case_name, \
- #test_name, \
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+ ::test_info_ =\
+ ::testing::internal::MakeAndRegisterTestInfo(\
+ #test_case_name, #test_name, "", "", \
::testing::internal::GetTypeId< parent_class >(), \
parent_class::SetUpTestCase, \
parent_class::TearDownTestCase, \
new ::testing::internal::TestFactoryImpl<\
- test_case_name##_##test_name##_Test>);\
-void test_case_name##_##test_name##_Test::TestBody()
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h
index 5be0d539..75429b2b 100644
--- a/include/gtest/internal/gtest-port.h
+++ b/include/gtest/internal/gtest-port.h
@@ -73,7 +73,10 @@
// Note that it is possible that none of the GTEST_OS_ macros are defined.
//
// Macros indicating available Google Test features:
-// GTEST_HAS_DEATH_TEST - defined iff death tests are supported.
+// GTEST_HAS_DEATH_TEST - defined iff death tests are supported.
+// GTEST_HAS_TYPED_TEST - defined iff typed tests are supported.
+// GTEST_HAS_TYPED_TEST_P - defined iff type-parameterized tests are
+// supported.
//
// Macros for basic C++ coding:
// GTEST_AMBIGUOUS_ELSE_BLOCKER - for disabling a gcc warning.
@@ -225,6 +228,15 @@
#include <sys/mman.h>
#endif // GTEST_HAS_STD_STRING && defined(GTEST_OS_LINUX)
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which gcc and VC
+// 8.0+ support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400)
+#define GTEST_HAS_TYPED_TEST
+#define GTEST_HAS_TYPED_TEST_P
+#endif // defined(__GNUC__) || (_MSC_VER >= 1400)
+
// Determines whether the system compiler uses UTF-16 for encoding wide strings.
#if defined(GTEST_OS_WINDOWS) || defined(GTEST_OS_CYGWIN) || \
defined(__SYMBIAN32__)
diff --git a/include/gtest/internal/gtest-string.h b/include/gtest/internal/gtest-string.h
index 612b6cef..b37ff4f4 100644
--- a/include/gtest/internal/gtest-string.h
+++ b/include/gtest/internal/gtest-string.h
@@ -167,6 +167,21 @@ class String {
static bool CaseInsensitiveCStringEquals(const char* lhs,
const char* rhs);
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+ static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs);
+
// Formats a list of arguments to a String, using the same format
// spec string as for printf.
//
@@ -218,6 +233,10 @@ class String {
return CStringEquals(c_str_, c_str);
}
+ // Returns true iff this String is less than the given C string. A NULL
+ // string is considered less than "".
+ bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
+
// Returns true iff this String doesn't equal the given C string. A NULL
// string and a non-NULL string are considered not equal.
bool operator!=(const char* c_str) const {