2

How can libraries such as GTest use a single macro G_TEST(...) to both define the function and register it as a test function? I'm looking for a way to do the same for my C99 project.

Example

#include <stdio.h>
#include "my_test_header_that_doesnt_exist.h"

TEST_MACRO(mytest)
{
    printf("Hello, world\n");
    return 0;
}
TEST_MACRO(mytest2)
{
    printf("Hello, world 2\n");
    return 2;
}

int main(int argc, char** argv)
{
    RUN_TESTS();
    return 0;
}

Can't figure out how to register the tests so they are known from RUN_TESTS()

  • Look at http://stackoverflow.com/questions/4880966/calling-some-functions-before-main-in-c to see how to ensure function in C is executed before main(). Then you can use this trick in your macros. Byteventurer answer properly explains how it is done in C++ but GTest - but you cannot use use this C++ specific trick... – PiotrNycz Aug 22 '16 at 11:35

1 Answers1

2

By passing an -E option to g++ you can inspect the code after preprocessing. Example code using the GTest library:

#include <gtest/gtest.h>

TEST(testcase, mytest) {
    // Code
}

int main() {
    return RUN_ALL_TESTS();
}

And compiling it with:

g++ -E -Igtest_include_path example.cpp -oexample_preprocessed.cpp

The TEST macro expanded to:

class testcase_mytest_Test : public ::testing::Test {
public:
    testcase_mytest_Test() {}
private:
    virtual void TestBody();
    static ::testing::TestInfo* const test_info_ __attribute__ ((unused));
    testcase_mytest_Test(testcase_mytest_Test const &);
    void operator=(testcase_mytest_Test const &);
};

::testing::TestInfo* const testcase_mytest_Test ::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "testcase", "mytest", __null, __null, ::testing::internal::CodeLocation("cpp_test.c", 3), (::testing::internal::GetTestTypeId()), ::testing::Test::SetUpTestCase, ::testing::Test::TearDownTestCase, new ::testing::internal::TestFactoryImpl< testcase_mytest_Test>);

void testcase_mytest_Test::TestBody() {
    // Code
}

And RUN_ALL_TESTS() is not a macro:

inline int RUN_ALL_TESTS() {
  return ::testing::UnitTest::GetInstance()->Run();
}

So it's in fact a complicated chain of preprocessor macros that make up a class out of your test case, and does all sorts of things to link it to the machinery that runs it.

Obviously you are not going to be able to do it like this in a C99 project, as GTest is a C++ library, and it heavily relies on C++ features to do the job.

If you wish to understand how it works fully, you should check out the GTest code in its repository: https://github.com/google/googletest

Franko Leon Tokalić
  • 1,457
  • 3
  • 22
  • 28