diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index 5def00b1..cefa564c 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -2354,6 +2354,92 @@ GTEST_API_ std::string TempDir(); # pragma warning(pop) #endif +// Dynamically registers a test with the framework. +// +// This is an advanced API only to be used when the `TEST` macros are +// insufficient. The macros should be preferred when possible, as they avoid +// most of the complexity of calling this function. +// +// The `factory` argument is a factory callable (move-constructible) object or +// function pointer that creates a new instance of the Test object. It +// handles ownership to the caller. The signature of the callable is +// `Fixture*()`, where `Fixture` is the test fixture class for the test. All +// tests registered with the same `test_case_name` must return the same +// fixture type. This is checked at runtime. +// +// The framework will infer the fixture class from the factory and will call +// the `SetUpTestCase` and `TearDownTestCase` for it. +// +// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +// undefined. +// +// Use case example: +// +// class MyFixture : public ::testing::Test { +// public: +// // All of these optional, just like in regular macro usage. +// static void SetUpTestCase() { ... } +// static void TearDownTestCase() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } +// }; +// +// class MyTest : public MyFixture { +// public: +// explicit MyTest(int data) : data_(data) {} +// void TestBody() override { ... } +// +// private: +// int data_; +// }; +// +// void RegisterMyTests(const std::vector& values) { +// for (int v : values) { +// ::testing::RegisterTest( +// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, +// std::to_string(v).c_str(), +// __FILE__, __LINE__, +// // Important to use the fixture type as the return type here. +// [=]() -> MyFixture* { return new MyTest(v); }); +// } +// } +// ... +// int main(int argc, char** argv) { +// std::vector values_to_test = LoadValuesFromConfig(); +// RegisterMyTests(values_to_test); +// ... +// return RUN_ALL_TESTS(); +// } +// +template +TestInfo* RegisterTest(const char* test_case_name, const char* test_name, + const char* type_param, const char* value_param, + const char* file, int line, Factory factory) { + using TestT = typename std::remove_pointer::type; + + // Helper class to get SetUpTestCase and TearDownTestCase when they are in a + // protected scope. + struct Helper : TestT { + using TestT::SetUpTestCase; + using TestT::TearDownTestCase; + }; + + class FactoryImpl : public internal::TestFactoryBase { + public: + explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} + Test* CreateTest() override { return factory_(); } + + private: + Factory factory_; + }; + + return internal::MakeAndRegisterTestInfo( + test_case_name, test_name, type_param, value_param, + internal::CodeLocation(file, line), internal::GetTypeId(), + &Helper::SetUpTestCase, &Helper::TearDownTestCase, + new FactoryImpl{std::move(factory)}); +} + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all diff --git a/googletest/test/googletest-output-test-golden-lin.txt b/googletest/test/googletest-output-test-golden-lin.txt index 86da845b..89a38e9e 100644 --- a/googletest/test/googletest-output-test-golden-lin.txt +++ b/googletest/test/googletest-output-test-golden-lin.txt @@ -12,7 +12,7 @@ Expected equality of these values: 3 Stack trace: (omitted) -[==========] Running 76 tests from 34 test cases. +[==========] Running 83 tests from 38 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. @@ -870,6 +870,84 @@ Expected non-fatal failure. Stack trace: (omitted) [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +[----------] 2 tests from DynamicFixture +DynamicFixture::SetUpTestCase +[ RUN ] DynamicFixture.DynamicTestPass +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] DynamicFixture.DynamicTestPass +[ RUN ] DynamicFixture.DynamicTestFail +DynamicFixture() +DynamicFixture::SetUp +googletest-output-test_.cc:#: Failure +Value of: Pass + Actual: false +Expected: true +Stack trace: (omitted) + +DynamicFixture::TearDown +~DynamicFixture() +[ FAILED ] DynamicFixture.DynamicTestFail +DynamicFixture::TearDownTestCase +[----------] 1 test from DynamicFixtureAnotherName +DynamicFixture::SetUpTestCase +[ RUN ] DynamicFixtureAnotherName.DynamicTestPass +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] DynamicFixtureAnotherName.DynamicTestPass +DynamicFixture::TearDownTestCase +[----------] 2 tests from BadDynamicFixture1 +DynamicFixture::SetUpTestCase +[ RUN ] BadDynamicFixture1.FixtureBase +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] BadDynamicFixture1.FixtureBase +[ RUN ] BadDynamicFixture1.TestBase +DynamicFixture() +gtest.cc:#: Failure +Failed +All tests in the same test case must use the same test fixture +class, so mixing TEST_F and TEST in the same test case is +illegal. In test case BadDynamicFixture1, +test FixtureBase is defined using TEST_F but +test TestBase is defined using TEST. You probably +want to change the TEST to TEST_F or move it to another test +case. +Stack trace: (omitted) + +~DynamicFixture() +[ FAILED ] BadDynamicFixture1.TestBase +DynamicFixture::TearDownTestCase +[----------] 2 tests from BadDynamicFixture2 +DynamicFixture::SetUpTestCase +[ RUN ] BadDynamicFixture2.FixtureBase +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] BadDynamicFixture2.FixtureBase +[ RUN ] BadDynamicFixture2.Derived +DynamicFixture() +gtest.cc:#: Failure +Failed +All tests in the same test case must use the same test fixture +class. However, in test case BadDynamicFixture2, +you defined test FixtureBase and test Derived +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test cases. +Stack trace: (omitted) + +~DynamicFixture() +[ FAILED ] BadDynamicFixture2.Derived +DynamicFixture::TearDownTestCase [----------] 1 test from PrintingFailingParams/FailingParamTest [ RUN ] PrintingFailingParams/FailingParamTest.Fails/0 googletest-output-test_.cc:#: Failure @@ -906,9 +984,9 @@ Failed Expected fatal failure. Stack trace: (omitted) -[==========] 76 tests from 34 test cases ran. -[ PASSED ] 26 tests. -[ FAILED ] 50 tests, listed below: +[==========] 83 tests from 38 test cases ran. +[ PASSED ] 30 tests. +[ FAILED ] 53 tests, listed below: [ FAILED ] NonfatalFailureTest.EscapesStringOperands [ FAILED ] NonfatalFailureTest.DiffForLongStrings [ FAILED ] FatalFailureTest.FatalFailureInSubroutine @@ -957,10 +1035,13 @@ Stack trace: (omitted) [ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure [ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +[ FAILED ] DynamicFixture.DynamicTestFail +[ FAILED ] BadDynamicFixture1.TestBase +[ FAILED ] BadDynamicFixture2.Derived [ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 [ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a" -50 FAILED TESTS +53 FAILED TESTS  YOU HAVE 1 DISABLED TEST Note: Google Test filter = FatalFailureTest.*:LoggingTest.* diff --git a/googletest/test/googletest-output-test_.cc b/googletest/test/googletest-output-test_.cc index 67de2d17..f86d814f 100644 --- a/googletest/test/googletest-output-test_.cc +++ b/googletest/test/googletest-output-test_.cc @@ -1024,6 +1024,56 @@ TEST_F(ExpectFailureTest, ExpectNonFatalFailureOnAllThreads) { "Some other non-fatal failure."); } +class DynamicFixture : public testing::Test { + protected: + DynamicFixture() { printf("DynamicFixture()\n"); } + ~DynamicFixture() override { printf("~DynamicFixture()\n"); } + void SetUp() override { printf("DynamicFixture::SetUp\n"); } + void TearDown() override { printf("DynamicFixture::TearDown\n"); } + + static void SetUpTestCase() { printf("DynamicFixture::SetUpTestCase\n"); } + static void TearDownTestCase() { + printf("DynamicFixture::TearDownTestCase\n"); + } +}; + +template +class DynamicTest : public DynamicFixture { + public: + void TestBody() override { EXPECT_TRUE(Pass); } +}; + +auto dynamic_test = ( + // Register two tests with the same fixture correctly. + testing::RegisterTest( + "DynamicFixture", "DynamicTestPass", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + testing::RegisterTest( + "DynamicFixture", "DynamicTestFail", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + + // Register the same fixture with another name. That's fine. + testing::RegisterTest( + "DynamicFixtureAnotherName", "DynamicTestPass", nullptr, nullptr, + __FILE__, __LINE__, + []() -> DynamicFixture* { return new DynamicTest; }), + + // Register two tests with the same fixture incorrectly. + testing::RegisterTest( + "BadDynamicFixture1", "FixtureBase", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + testing::RegisterTest( + "BadDynamicFixture1", "TestBase", nullptr, nullptr, __FILE__, __LINE__, + []() -> testing::Test* { return new DynamicTest; }), + + // Register two tests with the same fixture incorrectly by ommiting the + // return type. + testing::RegisterTest( + "BadDynamicFixture2", "FixtureBase", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + testing::RegisterTest("BadDynamicFixture2", "Derived", nullptr, nullptr, + __FILE__, __LINE__, + []() { return new DynamicTest; })); // Two test environments for testing testing::AddGlobalTestEnvironment(). diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index 9ddb37d0..6d9bd347 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -7547,3 +7547,30 @@ TEST_F(AdHocTestResultTest, AdHocTestResultTestForUnitTestDoesNotShowFailure) { testing::UnitTest::GetInstance()->ad_hoc_test_result(); EXPECT_FALSE(test_result.Failed()); } + +class DynamicUnitTestFixture : public testing::Test {}; + +class DynamicTest : public DynamicUnitTestFixture { + void TestBody() override { EXPECT_TRUE(true); } +}; + +auto* dynamic_test = testing::RegisterTest( + "DynamicUnitTestFixture", "DynamicTest", "TYPE", "VALUE", __FILE__, + __LINE__, []() -> DynamicUnitTestFixture* { return new DynamicTest; }); + +TEST(RegisterTest, WasRegistered) { + auto* unittest = testing::UnitTest::GetInstance(); + for (int i = 0; i < unittest->total_test_case_count(); ++i) { + auto* tests = unittest->GetTestCase(i); + if (tests->name() != std::string("DynamicUnitTestFixture")) continue; + for (int j = 0; j < tests->total_test_count(); ++j) { + if (tests->GetTestInfo(j)->name() != std::string("DynamicTest")) continue; + // Found it. + EXPECT_STREQ(tests->GetTestInfo(j)->value_param(), "VALUE"); + EXPECT_STREQ(tests->GetTestInfo(j)->type_param(), "TYPE"); + return; + } + } + + FAIL() << "Didn't find the test!"; +}