From a2b1a8556ea64014606d78b09333d9c522430a25 Mon Sep 17 00:00:00 2001 From: shiqian Date: Mon, 8 Sep 2008 17:55:52 +0000 Subject: Adds support for type-parameterized tests (by Zhanyong Wan); also adds case-insensitive wide string comparison to the String class (by Vlad Losev). --- Makefile.am | 43 ++++++- README | 19 ++- include/gtest/gtest.h | 83 ++++++------- include/gtest/internal/gtest-internal.h | 207 ++++++++++++++++++++++++++++++-- include/gtest/internal/gtest-port.h | 14 ++- include/gtest/internal/gtest-string.h | 19 +++ msvc/gtest.vcproj | 15 +++ src/gtest-internal-inl.h | 34 ++++-- src/gtest.cc | 171 +++++++++++++++++++------- test/gtest_nc.cc | 78 ++++++++++++ test/gtest_nc_test.py | 12 ++ test/gtest_output_test.py | 2 + test/gtest_output_test_.cc | 91 ++++++++++++++ test/gtest_output_test_golden_lin.txt | 58 ++++++++- test/gtest_output_test_golden_win.txt | 40 +++++- test/gtest_unittest.cc | 76 +++++++++++- xcode/gtest.xcodeproj/project.pbxproj | 105 ++++++++++++++-- 17 files changed, 930 insertions(+), 137 deletions(-) diff --git a/Makefile.am b/Makefile.am index c6e8707..1b0ee11 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,12 @@ # Automake file +# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump. + # Nonstandard package files for distribution EXTRA_DIST = \ CHANGES \ CONTRIBUTORS \ + include/gtest/internal/gtest-type-util.h.pump \ scripts/gen_gtest_pred_impl.py # MSVC project files @@ -19,6 +22,24 @@ EXTRA_DIST += \ msvc/gtest_uninitialized_test_.vcproj \ msvc/gtest_unittest.vcproj +# xcode project files +EXTRA_DIST += \ + xcode/Config/DebugProject.xcconfig \ + xcode/Config/FrameworkTarget.xcconfig \ + xcode/Config/General.xcconfig \ + xcode/Config/ReleaseProject.xcconfig \ + xcode/Resources/Info.plist \ + xcode/Scripts/versiongenerate.py \ + xcode/gtest.xcodeproj/project.pbxproj + +# xcode sample files +EXTRA_DIST += \ + xcode/Samples/FrameworkSample/Info.plist \ + xcode/Samples/FrameworkSample/widget_test.cc \ + xcode/Samples/FrameworkSample/widget.cc \ + xcode/Samples/FrameworkSample/widget.h \ + xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj + # TODO(wan@google.com): integrate scripts/gen_gtest_pred_impl.py into # the build system such that a user can specify the maximum predicate # arity here and have the script automatically generate the @@ -44,14 +65,16 @@ lib_libgtest_la_SOURCES = src/gtest.cc \ src/gtest-death-test.cc \ src/gtest-filepath.cc \ src/gtest-internal-inl.h \ - src/gtest-port.cc + src/gtest-port.cc \ + src/gtest-typed-test.cc pkginclude_HEADERS = include/gtest/gtest.h \ include/gtest/gtest-death-test.h \ include/gtest/gtest-message.h \ include/gtest/gtest-spi.h \ include/gtest/gtest_pred_impl.h \ - include/gtest/gtest_prod.h + include/gtest/gtest_prod.h \ + include/gtest/gtest-typed-test.h pkginclude_internaldir = $(pkgincludedir)/internal pkginclude_internal_HEADERS = \ @@ -59,7 +82,8 @@ pkginclude_internal_HEADERS = \ include/gtest/internal/gtest-filepath.h \ include/gtest/internal/gtest-internal.h \ include/gtest/internal/gtest-port.h \ - include/gtest/internal/gtest-string.h + include/gtest/internal/gtest-string.h \ + include/gtest/internal/gtest-type-util.h lib_libgtest_main_la_SOURCES = src/gtest_main.cc lib_libgtest_main_la_LIBADD = lib/libgtest.la @@ -116,6 +140,12 @@ samples_sample5_unittest_SOURCES = samples/sample5_unittest.cc samples_sample5_unittest_LDADD = lib/libgtest_main.la \ samples/libsamples.la +TESTS += samples/sample6_unittest +check_PROGRAMS += samples/sample6_unittest +samples_sample6_unittest_SOURCES = samples/sample6_unittest.cc +samples_sample6_unittest_LDADD = lib/libgtest_main.la \ + samples/libsamples.la + TESTS += test/gtest_unittest check_PROGRAMS += test/gtest_unittest test_gtest_unittest_SOURCES = test/gtest_unittest.cc @@ -179,6 +209,13 @@ check_PROGRAMS += test/gtest_stress_test test_gtest_stress_test_SOURCES = test/gtest_stress_test.cc test_gtest_stress_test_LDADD = lib/libgtest.la +TESTS += test/gtest-typed-test_test +check_PROGRAMS += test/gtest-typed-test_test +test_gtest_typed_test_test_SOURCES = test/gtest-typed-test_test.cc \ + test/gtest-typed-test2_test.cc \ + test/gtest-typed-test_test.h +test_gtest_typed_test_test_LDADD = lib/libgtest_main.la + # The following tests depend on the presence of a Python installation and are # keyed off of it. TODO(chandlerc@google.com): While we currently only attempt # to build and execute these tests if Autoconf has found Python v2.4 on the diff --git a/README b/README index 556c580..b2d455a 100644 --- a/README +++ b/README @@ -104,7 +104,6 @@ which contains all of the source code. Here are some examples in Linux: Building the Source ------------------- - ### Linux, Mac OS X (without Xcode), and Cygwin ### There are two primary options for building the source at this point: build it inside the source code tree, or in a separate directory. We recommend building @@ -173,4 +172,22 @@ in the "Variables to be set in the environment:" list, where you replace when you run your executable, it will load the framework and your test will run as expected. +Regenerating Source Files +------------------------- + +Some of Google Test's source files are generated from templates (not +in the C++ sense) using a script. A template file is named FOO.pump, +where FOO is the name of the file it will generate. For example, the +file include/gtest/internal/gtest-type-util.h.pump is used to generate +gtest-type-util.h in the same directory. + +Normally you don't need to worry about regenerating the source files, +unless you need to modify them (e.g. if you are working on a patch for +Google Test). In that case, you should modify the corresponding .pump +files instead and run the 'pump' script (for Pump is Useful for Meta +Programming) to regenerate them. We are still working on releasing +the script and its documentation. If you need it now, please email +googletestframework@googlegroups.com such that we know to make it +happen sooner. + Happy testing! diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index 1f5d764..37ea6b0 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 #include #include #include #include #include +#include // 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 dc6154b..8adf13e 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -46,11 +46,15 @@ #include #endif // GTEST_OS_LINUX -#include // NOLINT -#include // NOLINT +#include +#include +#include +#include +#include #include #include +#include // 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 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::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 +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 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().c_str()).c_str(), + "", + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::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 +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::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + 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 5be0d53..75429b2 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 #endif // GTEST_HAS_STD_STRING && defined(GTEST_OS_LINUX) +// Determines whether to support type-driven tests. + +// Typed tests need 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 612b6ce..b37ff4f 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 { diff --git a/msvc/gtest.vcproj b/msvc/gtest.vcproj index 3f2a5a6..47c4a80 100755 --- a/msvc/gtest.vcproj +++ b/msvc/gtest.vcproj @@ -145,6 +145,21 @@ + + + + + + + + diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 2633d69..6aafc7b 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -563,7 +563,8 @@ class TestResult { class TestInfoImpl { public: TestInfoImpl(TestInfo* parent, const char* test_case_name, - const char* name, TypeId fixture_class_id, + const char* name, const char* test_case_comment, + const char* comment, TypeId fixture_class_id, internal::TestFactoryBase* factory); ~TestInfoImpl(); @@ -585,6 +586,12 @@ class TestInfoImpl { // Returns the test name. const char* name() const { return name_.c_str(); } + // Returns the test case comment. + const char* test_case_comment() const { return test_case_comment_.c_str(); } + + // Returns the test comment. + const char* comment() const { return comment_.c_str(); } + // Returns the ID of the test fixture class. TypeId fixture_class_id() const { return fixture_class_id_; } @@ -611,12 +618,14 @@ class TestInfoImpl { private: // These fields are immutable properties of the test. - TestInfo* const parent_; // The owner of this object - const String test_case_name_; // Test case name - const String name_; // Test name - const TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled + TestInfo* const parent_; // The owner of this object + const String test_case_name_; // Test case name + const String name_; // Test name + const String test_case_comment_; // Test case comment + const String comment_; // Test comment + const TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -644,7 +653,7 @@ class TestCase { // name: name of the test case // 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 - TestCase(const char* name, + TestCase(const char* name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); @@ -654,6 +663,9 @@ class TestCase { // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } + // Returns the test case comment. + const char* comment() const { return comment_.c_str(); } + // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } @@ -739,6 +751,8 @@ class TestCase { private: // Name of the test case. internal::String name_; + // Comment on the test case. + internal::String comment_; // List of TestInfos. internal::List* test_info_list_; // Pointer to the function that sets up the test case. @@ -799,7 +813,7 @@ class UnitTestOptions { // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS - private: + // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const String& name, const char* filter); @@ -975,6 +989,7 @@ class UnitTestImpl : public TestPartResultReporterInterface { // 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 TestCase* GetTestCase(const char* test_case_name, + const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); @@ -989,6 +1004,7 @@ class UnitTestImpl : public TestPartResultReporterInterface { Test::TearDownTestCaseFunc tear_down_tc, TestInfo * test_info) { GetTestCase(test_info->test_case_name(), + test_info->test_case_comment(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } diff --git a/src/gtest.cc b/src/gtest.cc index 740eb74..09f6bae 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -40,6 +40,8 @@ #include #include #include +#include +#include #ifdef GTEST_OS_LINUX @@ -117,8 +119,14 @@ namespace testing { // Constants. -// A test that matches this pattern is disabled and not run. -static const char kDisableTestPattern[] = "DISABLED_*"; +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; @@ -1518,6 +1526,39 @@ bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { #endif // GTEST_OS_WINDOWS } + // 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. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + +#ifdef GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif defined(GTEST_OS_MAC) + // Mac OS X doesn't define wcscasecmp. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#else + return wcscasecmp(lhs, rhs) == 0; +#endif // OS selector +} + // Constructs a String by copying a given number of chars from a // buffer. E.g. String("hello", 3) will create the string "hel". String::String(const char * buffer, size_t len) { @@ -1716,8 +1757,8 @@ void TestResult::RecordProperty(const TestProperty& test_property) { property_with_matching_key.SetValue(test_property.value()); } -// Adds a failure if the key is a reserved attribute of Google Test testcase tags. -// Returns true if the property is valid. +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const TestProperty& test_property) { String key(test_property.key()); if (key == "name" || key == "status" || key == "time" || key == "classname") { @@ -1973,9 +2014,12 @@ bool Test::HasFatalFailure() { // object via impl_. TestInfo::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) { impl_ = new internal::TestInfoImpl(this, test_case_name, name, + test_case_comment, comment, fixture_class_id, factory); } @@ -1984,30 +2028,41 @@ TestInfo::~TestInfo() { delete impl_; } -// Creates a TestInfo object and registers it with the UnitTest -// singleton; returns the created object. +namespace internal { + +// 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 -// 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 factory object that creates a test object. The new -// TestInfo instance assumes ownership of the factory object. -TestInfo* 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) { +// 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) { TestInfo* const test_info = - new TestInfo(test_case_name, name, fixture_class_id, factory); - internal::GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + new TestInfo(test_case_name, name, test_case_comment, comment, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } +} // namespace internal + // Returns the test case name. const char* TestInfo::test_case_name() const { return impl_->test_case_name(); @@ -2018,6 +2073,16 @@ const char* TestInfo::name() const { return impl_->name(); } +// Returns the test case comment. +const char* TestInfo::test_case_comment() const { + return impl_->test_case_comment(); +} + +// Returns the test comment. +const char* TestInfo::comment() const { + return impl_->comment(); +} + // Returns true if this test should run. bool TestInfo::should_run() const { return impl_->should_run(); } @@ -2170,10 +2235,11 @@ int TestCase::total_test_count() const { // name: name of the test case // 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 -TestCase::TestCase(const char* name, +TestCase::TestCase(const char* name, const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(name), + comment_(comment), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), @@ -2283,18 +2349,11 @@ static const char * TestPartResultTypeToString(TestPartResultType type) { // Prints a TestPartResult. static void PrintTestPartResult( const TestPartResult & test_part_result) { - const char * const file_name = test_part_result.file_name(); - - printf("%s", file_name == NULL ? "unknown file" : file_name); - if (test_part_result.line_number() >= 0) { -#ifdef _MSC_VER - printf("(%d)", test_part_result.line_number()); -#else - printf(":%d", test_part_result.line_number()); -#endif - } - printf(": %s", TestPartResultTypeToString(test_part_result.type())); - printf("%s\n", test_part_result.message()); + printf("%s %s%s\n", + internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()).c_str(), + TestPartResultTypeToString(test_part_result.type()), + test_part_result.message()); fflush(stdout); } @@ -2471,7 +2530,12 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart( const internal::String counts = FormatCountableNoun(test_case->test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s\n", counts.c_str(), test_case_name_.c_str()); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case->comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_case->comment()); + } fflush(stdout); } @@ -2492,7 +2556,11 @@ void PrettyUnitTestResultPrinter::OnTestCaseEnd( void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_case_name_.c_str(), test_info->name()); - printf("\n"); + if (test_info->comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_info->comment()); + } fflush(stdout); } @@ -2553,7 +2621,16 @@ static void PrintFailedTestsPretty(const UnitTestImpl* impl) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s\n", ti->test_case_name(), ti->name()); + printf("%s.%s", ti->test_case_name(), ti->name()); + if (ti->test_case_comment()[0] != '\0' || + ti->comment()[0] != '\0') { + printf(", where %s", ti->test_case_comment()); + if (ti->test_case_comment()[0] != '\0' && + ti->comment()[0] != '\0') { + printf(" and "); + } + } + printf("%s\n", ti->comment()); } } } @@ -3244,6 +3321,7 @@ class TestCaseNameIs { // 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 TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* comment, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? @@ -3253,10 +3331,11 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, if (node == NULL) { // No. Let's create one. TestCase* const test_case = - new TestCase(test_case_name, set_up_tc, tear_down_tc); + new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); // Is this a death test case? - if (String(test_case_name).EndsWith("DeathTest")) { + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. node = test_cases_.InsertAfter(last_death_test_case_, test_case); @@ -3389,12 +3468,12 @@ int UnitTestImpl::FilterTests() { TestInfo * const test_info = test_info_node->element(); const String test_name(test_info->name()); // A test is disabled if test case name or test name matches - // kDisableTestPattern. + // kDisableTestFilter. const bool is_disabled = - internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern, - test_case_name.c_str()) || - internal::UnitTestOptions::PatternMatchesString(kDisableTestPattern, - test_name.c_str()); + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); const bool should_run = !is_disabled && @@ -3511,11 +3590,15 @@ internal::TestResult* UnitTestImpl::current_test_result() { TestInfoImpl::TestInfoImpl(TestInfo* parent, const char* test_case_name, const char* name, + const char* test_case_comment, + const char* comment, TypeId fixture_class_id, internal::TestFactoryBase* factory) : parent_(parent), test_case_name_(String(test_case_name)), name_(String(name)), + test_case_comment_(String(test_case_comment)), + comment_(String(comment)), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), diff --git a/test/gtest_nc.cc b/test/gtest_nc.cc index 001deb1..5cbaeef 100644 --- a/test/gtest_nc.cc +++ b/test/gtest_nc.cc @@ -103,6 +103,84 @@ class MyEnvironment : public testing::Environment { } }; +#elif defined(TEST_CATCHES_WRONG_CASE_IN_TYPED_TEST_P) +// Tests that the compiler catches using the wrong test case name in +// TYPED_TEST_P. + +#include + +template +class FooTest : public testing::Test { +}; + +template +class BarTest : public testing::Test { +}; + +TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_P(BarTest, A) {} // Wrong test case name. +REGISTER_TYPED_TEST_CASE_P(FooTest, A); +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types); + +#elif defined(TEST_CATCHES_WRONG_CASE_IN_REGISTER_TYPED_TEST_CASE_P) +// Tests that the compiler catches using the wrong test case name in +// REGISTER_TYPED_TEST_CASE_P. + +#include + +template +class FooTest : public testing::Test { +}; + +template +class BarTest : public testing::Test { +}; + +TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_P(FooTest, A) {} +REGISTER_TYPED_TEST_CASE_P(BarTest, A); // Wrong test case name. +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types); + +#elif defined(TEST_CATCHES_WRONG_CASE_IN_INSTANTIATE_TYPED_TEST_CASE_P) +// Tests that the compiler catches using the wrong test case name in +// INSTANTIATE_TYPED_TEST_CASE_P. + +#include + +template +class FooTest : public testing::Test { +}; + +template +class BarTest : public testing::Test { +}; + +TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_P(FooTest, A) {} +REGISTER_TYPED_TEST_CASE_P(FooTest, A); + +// Wrong test case name. +INSTANTIATE_TYPED_TEST_CASE_P(My, BarTest, testing::Types); + +#elif defined(TEST_CATCHES_INSTANTIATE_TYPED_TESET_CASE_P_WITH_SAME_NAME_PREFIX) +// Tests that the compiler catches instantiating TYPED_TEST_CASE_P +// twice with the same name prefix. + +#include + +template +class FooTest : public testing::Test { +}; + +TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_P(FooTest, A) {} +REGISTER_TYPED_TEST_CASE_P(FooTest, A); + +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types); + +// Wrong name prefix: "My" has been used. +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types); + #else // A sanity test. This should compile. diff --git a/test/gtest_nc_test.py b/test/gtest_nc_test.py index f63feaa..683bd37 100755 --- a/test/gtest_nc_test.py +++ b/test/gtest_nc_test.py @@ -66,6 +66,18 @@ class GTestNCTest(unittest.TestCase): ('CATCHES_CALLING_SETUP_IN_ENVIRONMENT_WITH_TYPO', [r'Setup_should_be_spelled_SetUp']), + ('CATCHES_WRONG_CASE_IN_TYPED_TEST_P', + [r'BarTest.*was not declared']), + + ('CATCHES_WRONG_CASE_IN_REGISTER_TYPED_TEST_CASE_P', + [r'BarTest.*was not declared']), + + ('CATCHES_WRONG_CASE_IN_INSTANTIATE_TYPED_TEST_CASE_P', + [r'BarTest.*not declared']), + + ('CATCHES_INSTANTIATE_TYPED_TESET_CASE_P_WITH_SAME_NAME_PREFIX', + [r'redefinition of.*My.*FooTest']), + ('SANITY', None) ] diff --git a/test/gtest_output_test.py b/test/gtest_output_test.py index 05f49dc..f91050c 100755 --- a/test/gtest_output_test.py +++ b/test/gtest_output_test.py @@ -32,6 +32,8 @@ """Tests the text output of Google C++ Testing Framework. SYNOPSIS + gtest_output_test.py --gtest_build_dir=BUILD/DIR --gengolden + # where BUILD/DIR contains the built gtest_output_test_ file. gtest_output_test.py --gengolden gtest_output_test.py """ diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc index d9f3f9e..758e18d 100644 --- a/test/gtest_output_test_.cc +++ b/test/gtest_output_test_.cc @@ -699,6 +699,97 @@ TEST(ExpectFatalFailureTest, FailsWhenStatementThrows) { #endif // GTEST_HAS_EXCEPTIONS +// This #ifdef block tests the output of typed tests. +#ifdef GTEST_HAS_TYPED_TEST + +template +class TypedTest : public testing::Test { +}; + +TYPED_TEST_CASE(TypedTest, testing::Types); + +TYPED_TEST(TypedTest, Success) { + EXPECT_EQ(0, TypeParam()); +} + +TYPED_TEST(TypedTest, Failure) { + EXPECT_EQ(1, TypeParam()) << "Expected failure"; +} + +#endif // GTEST_HAS_TYPED_TEST + +// This #ifdef block tests the output of type-parameterized tests. +#ifdef GTEST_HAS_TYPED_TEST_P + +template +class TypedTestP : public testing::Test { +}; + +TYPED_TEST_CASE_P(TypedTestP); + +TYPED_TEST_P(TypedTestP, Success) { + EXPECT_EQ(0, TypeParam()); +} + +TYPED_TEST_P(TypedTestP, Failure) { + EXPECT_EQ(1, TypeParam()) << "Expected failure"; +} + +REGISTER_TYPED_TEST_CASE_P(TypedTestP, Success, Failure); + +typedef testing::Types UnsignedTypes; +INSTANTIATE_TYPED_TEST_CASE_P(Unsigned, TypedTestP, UnsignedTypes); + +#endif // GTEST_HAS_TYPED_TEST_P + +#ifdef GTEST_HAS_DEATH_TEST + +// We rely on the golden file to verify that tests whose test case +// name ends with DeathTest are run first. + +TEST(ADeathTest, ShouldRunFirst) { +} + +#ifdef GTEST_HAS_TYPED_TEST + +// We rely on the golden file to verify that typed tests whose test +// case name ends with DeathTest are run first. + +template +class ATypedDeathTest : public testing::Test { +}; + +typedef testing::Types NumericTypes; +TYPED_TEST_CASE(ATypedDeathTest, NumericTypes); + +TYPED_TEST(ATypedDeathTest, ShouldRunFirst) { +} + +#endif // GTEST_HAS_TYPED_TEST + +#ifdef GTEST_HAS_TYPED_TEST_P + + +// We rely on the golden file to verify that type-parameterized tests +// whose test case name ends with DeathTest are run first. + +template +class ATypeParamDeathTest : public testing::Test { +}; + +TYPED_TEST_CASE_P(ATypeParamDeathTest); + +TYPED_TEST_P(ATypeParamDeathTest, ShouldRunFirst) { +} + +REGISTER_TYPED_TEST_CASE_P(ATypeParamDeathTest, ShouldRunFirst); + +INSTANTIATE_TYPED_TEST_CASE_P(My, ATypeParamDeathTest, NumericTypes); + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_HAS_DEATH_TEST + // Two test environments for testing testing::AddGlobalTestEnvironment(). class FooEnvironment : public testing::Environment { diff --git a/test/gtest_output_test_golden_lin.txt b/test/gtest_output_test_golden_lin.txt index 1da3bf3..e068bd2 100644 --- a/test/gtest_output_test_golden_lin.txt +++ b/test/gtest_output_test_golden_lin.txt @@ -7,10 +7,25 @@ Expected: true gtest_output_test_.cc:#: Failure Value of: 3 Expected: 2 -[==========] Running 37 tests from 13 test cases. +[==========] Running 48 tests from 21 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. +[----------] 1 test from ADeathTest +[ RUN ] ADeathTest.ShouldRunFirst +[ OK ] ADeathTest.ShouldRunFirst +[----------] 1 test from ATypedDeathTest/0, where TypeParam = int +[ RUN ] ATypedDeathTest/0.ShouldRunFirst +[ OK ] ATypedDeathTest/0.ShouldRunFirst +[----------] 1 test from ATypedDeathTest/1, where TypeParam = double +[ RUN ] ATypedDeathTest/1.ShouldRunFirst +[ OK ] ATypedDeathTest/1.ShouldRunFirst +[----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int +[ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst +[ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst +[----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double +[ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst +[ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) @@ -341,6 +356,36 @@ gtest.cc:#: Failure Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[----------] 2 tests from TypedTest/0, where TypeParam = int +[ RUN ] TypedTest/0.Success +[ OK ] TypedTest/0.Success +[ RUN ] TypedTest/0.Failure +gtest_output_test_.cc:#: Failure +Value of: TypeParam() + Actual: 0 +Expected: 1 +Expected failure +[ FAILED ] TypedTest/0.Failure +[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char +[ RUN ] Unsigned/TypedTestP/0.Success +[ OK ] Unsigned/TypedTestP/0.Success +[ RUN ] Unsigned/TypedTestP/0.Failure +gtest_output_test_.cc:#: Failure +Value of: TypeParam() + Actual: \0 +Expected: 1 +Expected failure +[ FAILED ] Unsigned/TypedTestP/0.Failure +[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int +[ RUN ] Unsigned/TypedTestP/1.Success +[ OK ] Unsigned/TypedTestP/1.Success +[ RUN ] Unsigned/TypedTestP/1.Failure +gtest_output_test_.cc:#: Failure +Value of: TypeParam() + Actual: 0 +Expected: 1 +Expected failure +[ FAILED ] Unsigned/TypedTestP/1.Failure [----------] Global test environment tear-down BarEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure @@ -350,9 +395,9 @@ FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. -[==========] 37 tests from 13 test cases ran. -[ PASSED ] 11 tests. -[ FAILED ] 26 tests, listed below: +[==========] 48 tests from 21 test cases ran. +[ PASSED ] 19 tests. +[ FAILED ] 29 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine @@ -379,8 +424,11 @@ Expected fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[ FAILED ] TypedTest/0.Failure, where TypeParam = int +[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char +[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int -26 FAILED TESTS +29 FAILED TESTS The non-test part of the code is expected to have 2 failures. gtest_output_test_.cc:#: Failure diff --git a/test/gtest_output_test_golden_win.txt b/test/gtest_output_test_golden_win.txt index 9a13da9..b88b85e 100644 --- a/test/gtest_output_test_golden_win.txt +++ b/test/gtest_output_test_golden_win.txt @@ -5,7 +5,7 @@ gtest_output_test_.cc:#: error: Value of: false Expected: true gtest_output_test_.cc:#: error: Value of: 3 Expected: 2 -[==========] Running 40 tests from 16 test cases. +[==========] Running 46 tests from 19 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. @@ -317,6 +317,33 @@ Expected non-fatal failure. gtest.cc:#: error: Expected: 1 fatal failure Actual: 0 failures [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[----------] 2 tests from TypedTest/0, where TypeParam = int +[ RUN ] TypedTest/0.Success +[ OK ] TypedTest/0.Success +[ RUN ] TypedTest/0.Failure +gtest_output_test_.cc:#: error: Value of: TypeParam() + Actual: 0 +Expected: 1 +Expected failure +[ FAILED ] TypedTest/0.Failure +[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char +[ RUN ] Unsigned/TypedTestP/0.Success +[ OK ] Unsigned/TypedTestP/0.Success +[ RUN ] Unsigned/TypedTestP/0.Failure +gtest_output_test_.cc:#: error: Value of: TypeParam() + Actual: \0 +Expected: 1 +Expected failure +[ FAILED ] Unsigned/TypedTestP/0.Failure +[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int +[ RUN ] Unsigned/TypedTestP/1.Success +[ OK ] Unsigned/TypedTestP/1.Success +[ RUN ] Unsigned/TypedTestP/1.Failure +gtest_output_test_.cc:#: error: Value of: TypeParam() + Actual: 0 +Expected: 1 +Expected failure +[ FAILED ] Unsigned/TypedTestP/1.Failure [----------] Global test environment tear-down BarEnvironment::TearDown() called. gtest_output_test_.cc:#: error: Failed @@ -324,9 +351,9 @@ Expected non-fatal failure. FooEnvironment::TearDown() called. gtest_output_test_.cc:#: error: Failed Expected fatal failure. -[==========] 40 tests from 16 test cases ran. -[ PASSED ] 11 tests. -[ FAILED ] 29 tests, listed below: +[==========] 46 tests from 19 test cases ran. +[ PASSED ] 14 tests. +[ FAILED ] 32 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine @@ -356,8 +383,11 @@ Expected fatal failure. [ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures [ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure [ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[ FAILED ] TypedTest/0.Failure, where TypeParam = int +[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char +[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int -29 FAILED TESTS +32 FAILED TESTS The non-test part of the code is expected to have 2 failures. gtest_output_test_.cc:#: error: Value of: false diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index eecaf4e..7c5123c 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -529,6 +529,18 @@ TEST(StringTest, EndsWithCaseInsensitive) { EXPECT_FALSE(String("").EndsWithCaseInsensitive("foo")); } +// Tests String::CaseInsensitiveWideCStringEquals +TEST(StringTest, CaseInsensitiveWideCStringEquals) { + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(NULL, NULL)); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(NULL, L"")); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"", NULL)); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(NULL, L"foobar")); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"foobar", NULL)); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"foobar")); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"FOOBAR")); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"FOOBAR", L"foobar")); +} + // Tests that NULL can be assigned to a String. TEST(StringTest, CanBeAssignedNULL) { const String src(NULL); @@ -2134,6 +2146,68 @@ TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_2) { FAIL() << "Unexpected failure: Disabled test should not be run."; } +// Tests that disabled typed tests aren't run. + +#ifdef GTEST_HAS_TYPED_TEST + +template +class TypedTest : public Test { +}; + +typedef testing::Types NumericTypes; +TYPED_TEST_CASE(TypedTest, NumericTypes); + +TYPED_TEST(TypedTest, DISABLED_ShouldNotRun) { + FAIL() << "Unexpected failure: Disabled typed test should not run."; +} + +template +class DISABLED_TypedTest : public Test { +}; + +TYPED_TEST_CASE(DISABLED_TypedTest, NumericTypes); + +TYPED_TEST(DISABLED_TypedTest, ShouldNotRun) { + FAIL() << "Unexpected failure: Disabled typed test should not run."; +} + +#endif // GTEST_HAS_TYPED_TEST + +// Tests that disabled type-parameterized tests aren't run. + +#ifdef GTEST_HAS_TYPED_TEST_P + +template +class TypedTestP : public Test { +}; + +TYPED_TEST_CASE_P(TypedTestP); + +TYPED_TEST_P(TypedTestP, DISABLED_ShouldNotRun) { + FAIL() << "Unexpected failure: " + << "Disabled type-parameterized test should not run."; +} + +REGISTER_TYPED_TEST_CASE_P(TypedTestP, DISABLED_ShouldNotRun); + +INSTANTIATE_TYPED_TEST_CASE_P(My, TypedTestP, NumericTypes); + +template +class DISABLED_TypedTestP : public Test { +}; + +TYPED_TEST_CASE_P(DISABLED_TypedTestP); + +TYPED_TEST_P(DISABLED_TypedTestP, ShouldNotRun) { + FAIL() << "Unexpected failure: " + << "Disabled type-parameterized test should not run."; +} + +REGISTER_TYPED_TEST_CASE_P(DISABLED_TypedTestP, ShouldNotRun); + +INSTANTIATE_TYPED_TEST_CASE_P(My, DISABLED_TypedTestP, NumericTypes); + +#endif // GTEST_HAS_TYPED_TEST_P // Tests that assertion macros evaluate their arguments exactly once. @@ -3491,7 +3565,7 @@ class TestInfoTest : public Test { protected: static TestInfo * GetTestInfo(const char* test_name) { return UnitTest::GetInstance()->impl()-> - GetTestCase("TestInfoTest", NULL, NULL)-> + GetTestCase("TestInfoTest", "", NULL, NULL)-> GetTestInfo(test_name); } diff --git a/xcode/gtest.xcodeproj/project.pbxproj b/xcode/gtest.xcodeproj/project.pbxproj index 9bc4a8b..344dbf1 100644 --- a/xcode/gtest.xcodeproj/project.pbxproj +++ b/xcode/gtest.xcodeproj/project.pbxproj @@ -22,6 +22,9 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 22A865FD0E70A35700F7AE6E /* gtest-typed-test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 22A865FC0E70A35700F7AE6E /* gtest-typed-test.cc */; }; + 22A866080E70A39900F7AE6E /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D07F2C80486CC7A007CD1D0 /* gtest.framework */; }; + 22A866190E70A41000F7AE6E /* sample6_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 22A866180E70A41000F7AE6E /* sample6_unittest.cc */; }; 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DB0E2F799B00CF7658 /* gtest-death-test.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404884390E2F799B00CF7658 /* gtest-message.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DC0E2F799B00CF7658 /* gtest-message.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DD0E2F799B00CF7658 /* gtest-spi.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -59,6 +62,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 22A866030E70A39900F7AE6E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0; + remoteInfo = gtest; + }; 404885A70E2F824900CF7658 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -98,7 +108,7 @@ isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; - remoteGlobalIDString = 40C44ADC0E3798F4008FCC51 /* Version.h */; + remoteGlobalIDString = 40C44ADC0E3798F4008FCC51; remoteInfo = Version.h; }; /* End PBXContainerItemProxy section */ @@ -122,6 +132,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 22A865FC0E70A35700F7AE6E /* gtest-typed-test.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "gtest-typed-test.cc"; sourceTree = ""; }; + 22A8660C0E70A39900F7AE6E /* sample6 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sample6; sourceTree = BUILT_PRODUCTS_DIR; }; + 22A866180E70A41000F7AE6E /* sample6_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = sample6_unittest.cc; sourceTree = ""; }; 403EE37C0E377822004BD1E2 /* versiongenerate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = versiongenerate.py; sourceTree = ""; }; 404883DB0E2F799B00CF7658 /* gtest-death-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test.h"; sourceTree = ""; }; 404883DC0E2F799B00CF7658 /* gtest-message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-message.h"; sourceTree = ""; }; @@ -156,8 +169,8 @@ 404884A90E2F7CD900CF7658 /* CHANGES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CHANGES; path = ../CHANGES; sourceTree = SOURCE_ROOT; }; 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CONTRIBUTORS; path = ../CONTRIBUTORS; sourceTree = SOURCE_ROOT; }; 404884AB0E2F7CD900CF7658 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING; path = ../COPYING; sourceTree = SOURCE_ROOT; }; - 404885930E2F814C00CF7658 /* sample1 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sample1; sourceTree = BUILT_PRODUCTS_DIR; }; - 404885BB0E2F82BA00CF7658 /* sample3 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sample3; sourceTree = BUILT_PRODUCTS_DIR; }; + 404885930E2F814C00CF7658 /* sample1 */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = sample1; sourceTree = BUILT_PRODUCTS_DIR; }; + 404885BB0E2F82BA00CF7658 /* sample2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sample2; sourceTree = BUILT_PRODUCTS_DIR; }; 404885DF0E2F832A00CF7658 /* sample3 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sample3; sourceTree = BUILT_PRODUCTS_DIR; }; 404885EC0E2F833000CF7658 /* sample4 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sample4; sourceTree = BUILT_PRODUCTS_DIR; }; 404885F90E2F833400CF7658 /* sample5 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sample5; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -165,11 +178,19 @@ 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FrameworkTarget.xcconfig; sourceTree = ""; }; 40D4CDF30E30E07400294801 /* General.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = ""; }; 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseProject.xcconfig; sourceTree = ""; }; - 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; explicitFileType = text.plist.xml; fileEncoding = 4; path = Info.plist; sourceTree = ""; }; + 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Info.plist; sourceTree = ""; }; 8D07F2C80486CC7A007CD1D0 /* gtest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = gtest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 22A866070E70A39900F7AE6E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 22A866080E70A39900F7AE6E /* gtest.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 404885910E2F814C00CF7658 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -225,10 +246,11 @@ children = ( 8D07F2C80486CC7A007CD1D0 /* gtest.framework */, 404885930E2F814C00CF7658 /* sample1 */, - 404885BB0E2F82BA00CF7658 /* sample3 */, + 404885BB0E2F82BA00CF7658 /* sample2 */, 404885DF0E2F832A00CF7658 /* sample3 */, 404885EC0E2F833000CF7658 /* sample4 */, 404885F90E2F833400CF7658 /* sample5 */, + 22A8660C0E70A39900F7AE6E /* sample6 */, ); name = Products; sourceTree = ""; @@ -317,6 +339,7 @@ 404884010E2F799B00CF7658 /* sample4.h */, 404884020E2F799B00CF7658 /* sample4_unittest.cc */, 404884030E2F799B00CF7658 /* sample5_unittest.cc */, + 22A866180E70A41000F7AE6E /* sample6_unittest.cc */, ); name = samples; path = ../samples; @@ -331,6 +354,7 @@ 4048840B0E2F799B00CF7658 /* gtest-port.cc */, 4048840C0E2F799B00CF7658 /* gtest.cc */, 4048840D0E2F799B00CF7658 /* gtest_main.cc */, + 22A865FC0E70A35700F7AE6E /* gtest-typed-test.cc */, ); name = src; path = ../src; @@ -374,6 +398,23 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 22A866010E70A39900F7AE6E /* sample6 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 22A866090E70A39900F7AE6E /* Build configuration list for PBXNativeTarget "sample6" */; + buildPhases = ( + 22A866040E70A39900F7AE6E /* Sources */, + 22A866070E70A39900F7AE6E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 22A866020E70A39900F7AE6E /* PBXTargetDependency */, + ); + name = sample6; + productName = sample6; + productReference = 22A8660C0E70A39900F7AE6E /* sample6 */; + productType = "com.apple.product-type.tool"; + }; 404885920E2F814C00CF7658 /* sample1 */ = { isa = PBXNativeTarget; buildConfigurationList = 4048859E0E2F818900CF7658 /* Build configuration list for PBXNativeTarget "sample1" */; @@ -404,8 +445,8 @@ 404885B10E2F82BA00CF7658 /* PBXTargetDependency */, ); name = sample2; - productName = sample1; - productReference = 404885BB0E2F82BA00CF7658 /* sample3 */; + productName = sample2; + productReference = 404885BB0E2F82BA00CF7658 /* sample2 */; productType = "com.apple.product-type.tool"; }; 404885D40E2F832A00CF7658 /* sample3 */ = { @@ -421,7 +462,7 @@ 404885D50E2F832A00CF7658 /* PBXTargetDependency */, ); name = sample3; - productName = sample1; + productName = sample3; productReference = 404885DF0E2F832A00CF7658 /* sample3 */; productType = "com.apple.product-type.tool"; }; @@ -438,7 +479,7 @@ 404885E20E2F833000CF7658 /* PBXTargetDependency */, ); name = sample4; - productName = sample1; + productName = sample4; productReference = 404885EC0E2F833000CF7658 /* sample4 */; productType = "com.apple.product-type.tool"; }; @@ -455,7 +496,7 @@ 404885EF0E2F833400CF7658 /* PBXTargetDependency */, ); name = sample5; - productName = sample1; + productName = sample5; productReference = 404885F90E2F833400CF7658 /* sample5 */; productType = "com.apple.product-type.tool"; }; @@ -507,6 +548,7 @@ 404885D40E2F832A00CF7658 /* sample3 */, 404885E10E2F833000CF7658 /* sample4 */, 404885EE0E2F833400CF7658 /* sample5 */, + 22A866010E70A39900F7AE6E /* sample6 */, 40C44ADC0E3798F4008FCC51 /* Version Info */, ); }; @@ -557,6 +599,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 22A866040E70A39900F7AE6E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 22A866190E70A41000F7AE6E /* sample6_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 404885900E2F814C00CF7658 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -610,12 +660,18 @@ 404884620E2F799B00CF7658 /* gtest-port.cc in Sources */, 404884630E2F799B00CF7658 /* gtest.cc in Sources */, 404884640E2F799B00CF7658 /* gtest_main.cc in Sources */, + 22A865FD0E70A35700F7AE6E /* gtest-typed-test.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 22A866020E70A39900F7AE6E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8D07F2BC0486CC7A007CD1D0 /* gtest */; + targetProxy = 22A866030E70A39900F7AE6E /* PBXContainerItemProxy */; + }; 404885A80E2F824900CF7658 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8D07F2BC0486CC7A007CD1D0 /* gtest */; @@ -649,6 +705,22 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 22A8660A0E70A39900F7AE6E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = sample6; + }; + name = Debug; + }; + 22A8660B0E70A39900F7AE6E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = sample6; + }; + name = Release; + }; 404885950E2F814C00CF7658 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -669,7 +741,7 @@ isa = XCBuildConfiguration; buildSettings = { INSTALL_PATH = /usr/local/bin; - PRODUCT_NAME = sample3; + PRODUCT_NAME = sample2; }; name = Debug; }; @@ -677,7 +749,7 @@ isa = XCBuildConfiguration; buildSettings = { INSTALL_PATH = /usr/local/bin; - PRODUCT_NAME = sample3; + PRODUCT_NAME = sample2; }; name = Release; }; @@ -798,6 +870,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 22A866090E70A39900F7AE6E /* Build configuration list for PBXNativeTarget "sample6" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 22A8660A0E70A39900F7AE6E /* Debug */, + 22A8660B0E70A39900F7AE6E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 4048859E0E2F818900CF7658 /* Build configuration list for PBXNativeTarget "sample1" */ = { isa = XCConfigurationList; buildConfigurations = ( -- cgit v0.12