diff options
| author | shiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925> | 2008-09-08 17:55:52 +0000 | 
|---|---|---|
| committer | shiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925> | 2008-09-08 17:55:52 +0000 | 
| commit | a2b1a8556ea64014606d78b09333d9c522430a25 (patch) | |
| tree | a4f4a88d89b4f957655a479bba3f33908572fcb5 /include | |
| parent | 0c5a66245b8c5939b36b2aad6f4d5ab89b724b1a (diff) | |
| download | googletest-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.h | 83 | ||||
| -rw-r--r-- | include/gtest/internal/gtest-internal.h | 207 | ||||
| -rw-r--r-- | include/gtest/internal/gtest-port.h | 14 | ||||
| -rw-r--r-- | include/gtest/internal/gtest-string.h | 19 | 
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 { | 
