From f39f567a90c175ca2c440293714ae97caa02c654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 14 Aug 2024 11:05:32 +0200 Subject: [PATCH] refs #12080 - testrunner: do not create test implementation until it is used (#6691) Greatly improves the start-up time because it no longer needs to create all the implementations before it runs any test. The following times are using a debug build. Before: `bin/testrunner TestColor 1,16s user 0,07s system 99% cpu 1,235 total` After: `bin/testrunner TestColor 0,00s user 0,00s system 88% cpu 0,009 total` --- test/fixture.cpp | 23 +++++++++++++---------- test/fixture.h | 14 +++++++++++++- test/testmemleak.cpp | 2 +- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/test/fixture.cpp b/test/fixture.cpp index 6f79bd70f96..a13ccf2c803 100644 --- a/test/fixture.cpp +++ b/test/fixture.cpp @@ -41,12 +41,12 @@ **/ namespace { struct CompareFixtures { - bool operator()(const TestFixture* lhs, const TestFixture* rhs) const { + bool operator()(const TestInstance* lhs, const TestInstance* rhs) const { return lhs->classname < rhs->classname; } }; } -using TestSet = std::set; +using TestSet = std::set; namespace { class TestRegistry { TestSet _tests; @@ -57,7 +57,7 @@ namespace { return testreg; } - void addTest(TestFixture *t) { + void addTest(TestInstance *t) { _tests.insert(t); } @@ -67,7 +67,11 @@ namespace { }; } - +TestInstance::TestInstance(const char * _name) + : classname(_name) +{ + TestRegistry::theInstance().addTest(this); +} /** @@ -83,9 +87,7 @@ std::size_t TestFixture::succeeded_todos_counter = 0; TestFixture::TestFixture(const char * const _name) : classname(_name) -{ - TestRegistry::theInstance().addTest(this); -} +{} bool TestFixture::prepareTest(const char testname[]) @@ -389,10 +391,11 @@ std::size_t TestFixture::runTests(const options& args) classname.erase(classname.find("::")); } - for (TestFixture * test : TestRegistry::theInstance().tests()) { + for (TestInstance * test : TestRegistry::theInstance().tests()) { if (classname.empty() || test->classname == classname) { - test->processOptions(args); - test->run(testname); + TestFixture* fixture = test->create(); + fixture->processOptions(args); + fixture->run(testname); } } } diff --git a/test/fixture.h b/test/fixture.h index fc88c50cb10..c44e45fa1b2 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -283,6 +283,18 @@ class TestFixture : public ErrorLogger { static std::size_t runTests(const options& args); }; +class TestInstance { +public: + explicit TestInstance(const char * _name); + virtual ~TestInstance() = default; + + virtual TestFixture* create() = 0; + + const std::string classname; +protected: + std::unique_ptr impl; +}; + // TODO: most asserts do not actually assert i.e. do not return #define TEST_CASE( NAME ) do { if (prepareTest(#NAME)) { setVerbose(false); try { NAME(); teardownTest(); } catch (...) { assertNoThrowFail(__FILE__, __LINE__); } } } while (false) #define ASSERT( CONDITION ) if (!assert_(__FILE__, __LINE__, (CONDITION))) return @@ -306,7 +318,7 @@ class TestFixture : public ErrorLogger { #define TODO_ASSERT( CONDITION ) do { const bool condition=(CONDITION); todoAssertEquals(__FILE__, __LINE__, true, false, condition); } while (false) #define TODO_ASSERT_EQUALS( WANTED, CURRENT, ACTUAL ) todoAssertEquals(__FILE__, __LINE__, WANTED, CURRENT, ACTUAL) #define EXPECT_EQ( EXPECTED, ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL) -#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance_ ## CLASSNAME; } +#define REGISTER_TEST( CLASSNAME ) namespace { class CLASSNAME ## Instance : public TestInstance { public: CLASSNAME ## Instance() : TestInstance(#CLASSNAME) {} TestFixture* create() override { impl.reset(new CLASSNAME); return impl.get(); } }; CLASSNAME ## Instance instance_ ## CLASSNAME; } #define PLATFORM( P, T ) do { std::string errstr; assertEquals(__FILE__, __LINE__, true, P.set(Platform::toString(T), errstr, {exename}), errstr); } while (false) diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 7dd63503208..572122b5965 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -27,7 +27,7 @@ #include #include -class TestMemleak : private TestFixture { +class TestMemleak : public TestFixture { public: TestMemleak() : TestFixture("TestMemleak") {}