diff --git a/README.md b/README.md index ca471f4..8a49bd2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,15 @@ The current supported compilers are gcc, clang and msvc. -The current tested compiler versions are gcc 4.8.2, clang 3.5 and MSVC 18.0.21005.1. +The current supported platforms are Linux, Mac OSX and Windows. + +## Command Line Options ## + +utest.h supports some command line options: + +* --help to output the help message +* --filter= will filter the test cases to run (useful for re-running one particular offending test case). +* --output= will output an xunit XML file with the test results (that Jenkins, travis-ci, and appveyor can parse for the test results). ## Design ## @@ -24,25 +32,125 @@ [==========] 1 test cases ran. [ PASSED ] 1 tests. +## UTEST_MAIN ## + +In one C or C++ file, you must call the macro UTEST_MAIN: + + UTEST_MAIN(); + +This will call into utest.h, instantiate all the testcases and run the unit test framework. + +Alternatively, if you want to write your own main and call into utest.h, you can instead, in one C or C++ file call: + + UTEST_STATE(); + +And then when you are ready to call into the utest.h framework do: + + int main(int argc, const char *const argv[]) { + // do your own thing + return utest_main(argc, argv); + } + +## Define a Testcase ## + To define a test case to run, you can do the following; #include "utest.h" - TESTCASE(foo, bar) { + UTEST(foo, bar) { ASSERT_TRUE(1); } -The TESTCASE macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. +The UTEST macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. + +## Define a Fixtured Testcase ## + +A fixtured testcase is one in which there is a struct that is instantiated that can be shared across multiple testcases. + + struct MyTestFixture { + char c; + int i; + float f; + }; + + UTEST_F_SETUP(MyTestFixture) { + utest_fixture->c = 'a'; + utest_fixture->i = 42; + utest_fixture->f = 3.14f; + + // we can even assert and expect in setup! + ASSERT_EQ(42, utest_fixture->i); + EXPECT_TRUE(true); + } + + UTEST_F_TEARDOWN(MyTestFixture) { + // and also assert and expect in teardown! + ASSERT_EQ(13, utest_fixture->i); + } + + UTEST_F(MyTestFixture, a) { + utest_fixture->i = 13; + // teardown will succeed because i is 13... + } + + UTEST_F(MyTestFixture, b) { + utest_fixture->i = 83; + // teardown will fail because i is not 13! + } + +Some things to note that were demonstrated above: +* We have this new implicit variable within our macros - utest_fixture. This is a pointer to the struct you decidedw as your fixture (so MyTestFixture in the above code). +* Instead of specifying a testcase set (like we do with the UTEST macro), we instead specify the name of the fixture struct we are use. +* Every fixture has to have a UTEST_F_SETUP and UTEST_F_TEARDOWN macro - even if they do nothing in the body of them. +* Multiple testcases (UTEST_F's) can use the same fixture. +* You can use EXPECT_* and ASSERT_* macros within the body of both the fixture's setup and teardown macros. + +## Define an Indexed Testcase ## + +Sometimes you want to use the same fixture _and_ testcase repeatedly, but prehaps subtly change one variable within. This is where indexed testcases come in. + + struct MyTestIndexedFixture{ + bool x; + bool y; + }; + + UTEST_I_SETUP(MyTestIndexedFixture) { + if (utest_index < 30) { + utest_fixture->x = utest_index & 1; + utest_fixture->y = (utest_index + 1) & 1; + } + } + + UTEST_I_TEARDOWN(MyTestIndexedFixture) { + EXPECT_LE(0, utest_index); + } + + UTEST_I(MyTestIndexedFixture, a, 2) { + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + + UTEST_I(MyTestIndexedFixture, b, 42) { + // this will fail when the index is >= 30 + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + +Note: +* We use UTEST_I_* as the prefix for the setup and teardown functions now. +* We use UTEST_I to declare the testcases. +* We have access to a new variable utest_index in our setup and teardown functions, that we can use to slightly vary our fixture. +* We provide a number as the third parameter of the UTEST_I macro - this is the number of times we should run the test case for that index. It must be a literal. + +## Testing Macros ## Matching what googletest has, we provide two variants of each of the error checking conditions - ASSERT's and EXPECT's. If an ASSERT fails, the test case will cease execution, and utest.h will continue with the next test case to be run. If an EXPECT fails, the remainder of the test case will still be executed, allowing for further checks to be carried out. -We currently provide the following macros to be used within TESTCASE's. +We currently provide the following macros to be used within UTEST's. ### ASSERT_TRUE(x) ### Asserts that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; ASSERT_TRUE(i); // pass! ASSERT_TRUE(42); // pass! @@ -53,7 +161,7 @@ Asserts that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; ASSERT_FALSE(i); // pass! ASSERT_FALSE(1); // fail! @@ -63,7 +171,7 @@ Asserts that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; ASSERT_EQ(a, b); // pass! @@ -77,7 +185,7 @@ Asserts that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_NE(a, b); // pass! @@ -91,7 +199,7 @@ Asserts that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LT(a, b); // pass! @@ -105,7 +213,7 @@ Asserts that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LE(a, b); // pass! @@ -122,7 +230,7 @@ Asserts that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GT(a, b); // pass! @@ -136,7 +244,7 @@ Asserts that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GE(a, b); // pass! @@ -153,7 +261,7 @@ Expects that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; EXPECT_TRUE(i); // pass! EXPECT_TRUE(42); // pass! @@ -164,7 +272,7 @@ Expects that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; EXPECT_FALSE(i); // pass! EXPECT_FALSE(1); // fail! @@ -174,7 +282,7 @@ Expects that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; EXPECT_EQ(a, b); // pass! @@ -188,7 +296,7 @@ Expects that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_NE(a, b); // pass! @@ -202,7 +310,7 @@ Expects that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LT(a, b); // pass! @@ -216,7 +324,7 @@ Expects that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LE(a, b); // pass! @@ -233,7 +341,7 @@ Expects that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GT(a, b); // pass! @@ -247,7 +355,7 @@ Expects that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GE(a, b); // pass! diff --git a/README.md b/README.md index ca471f4..8a49bd2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,15 @@ The current supported compilers are gcc, clang and msvc. -The current tested compiler versions are gcc 4.8.2, clang 3.5 and MSVC 18.0.21005.1. +The current supported platforms are Linux, Mac OSX and Windows. + +## Command Line Options ## + +utest.h supports some command line options: + +* --help to output the help message +* --filter= will filter the test cases to run (useful for re-running one particular offending test case). +* --output= will output an xunit XML file with the test results (that Jenkins, travis-ci, and appveyor can parse for the test results). ## Design ## @@ -24,25 +32,125 @@ [==========] 1 test cases ran. [ PASSED ] 1 tests. +## UTEST_MAIN ## + +In one C or C++ file, you must call the macro UTEST_MAIN: + + UTEST_MAIN(); + +This will call into utest.h, instantiate all the testcases and run the unit test framework. + +Alternatively, if you want to write your own main and call into utest.h, you can instead, in one C or C++ file call: + + UTEST_STATE(); + +And then when you are ready to call into the utest.h framework do: + + int main(int argc, const char *const argv[]) { + // do your own thing + return utest_main(argc, argv); + } + +## Define a Testcase ## + To define a test case to run, you can do the following; #include "utest.h" - TESTCASE(foo, bar) { + UTEST(foo, bar) { ASSERT_TRUE(1); } -The TESTCASE macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. +The UTEST macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. + +## Define a Fixtured Testcase ## + +A fixtured testcase is one in which there is a struct that is instantiated that can be shared across multiple testcases. + + struct MyTestFixture { + char c; + int i; + float f; + }; + + UTEST_F_SETUP(MyTestFixture) { + utest_fixture->c = 'a'; + utest_fixture->i = 42; + utest_fixture->f = 3.14f; + + // we can even assert and expect in setup! + ASSERT_EQ(42, utest_fixture->i); + EXPECT_TRUE(true); + } + + UTEST_F_TEARDOWN(MyTestFixture) { + // and also assert and expect in teardown! + ASSERT_EQ(13, utest_fixture->i); + } + + UTEST_F(MyTestFixture, a) { + utest_fixture->i = 13; + // teardown will succeed because i is 13... + } + + UTEST_F(MyTestFixture, b) { + utest_fixture->i = 83; + // teardown will fail because i is not 13! + } + +Some things to note that were demonstrated above: +* We have this new implicit variable within our macros - utest_fixture. This is a pointer to the struct you decidedw as your fixture (so MyTestFixture in the above code). +* Instead of specifying a testcase set (like we do with the UTEST macro), we instead specify the name of the fixture struct we are use. +* Every fixture has to have a UTEST_F_SETUP and UTEST_F_TEARDOWN macro - even if they do nothing in the body of them. +* Multiple testcases (UTEST_F's) can use the same fixture. +* You can use EXPECT_* and ASSERT_* macros within the body of both the fixture's setup and teardown macros. + +## Define an Indexed Testcase ## + +Sometimes you want to use the same fixture _and_ testcase repeatedly, but prehaps subtly change one variable within. This is where indexed testcases come in. + + struct MyTestIndexedFixture{ + bool x; + bool y; + }; + + UTEST_I_SETUP(MyTestIndexedFixture) { + if (utest_index < 30) { + utest_fixture->x = utest_index & 1; + utest_fixture->y = (utest_index + 1) & 1; + } + } + + UTEST_I_TEARDOWN(MyTestIndexedFixture) { + EXPECT_LE(0, utest_index); + } + + UTEST_I(MyTestIndexedFixture, a, 2) { + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + + UTEST_I(MyTestIndexedFixture, b, 42) { + // this will fail when the index is >= 30 + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + +Note: +* We use UTEST_I_* as the prefix for the setup and teardown functions now. +* We use UTEST_I to declare the testcases. +* We have access to a new variable utest_index in our setup and teardown functions, that we can use to slightly vary our fixture. +* We provide a number as the third parameter of the UTEST_I macro - this is the number of times we should run the test case for that index. It must be a literal. + +## Testing Macros ## Matching what googletest has, we provide two variants of each of the error checking conditions - ASSERT's and EXPECT's. If an ASSERT fails, the test case will cease execution, and utest.h will continue with the next test case to be run. If an EXPECT fails, the remainder of the test case will still be executed, allowing for further checks to be carried out. -We currently provide the following macros to be used within TESTCASE's. +We currently provide the following macros to be used within UTEST's. ### ASSERT_TRUE(x) ### Asserts that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; ASSERT_TRUE(i); // pass! ASSERT_TRUE(42); // pass! @@ -53,7 +161,7 @@ Asserts that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; ASSERT_FALSE(i); // pass! ASSERT_FALSE(1); // fail! @@ -63,7 +171,7 @@ Asserts that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; ASSERT_EQ(a, b); // pass! @@ -77,7 +185,7 @@ Asserts that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_NE(a, b); // pass! @@ -91,7 +199,7 @@ Asserts that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LT(a, b); // pass! @@ -105,7 +213,7 @@ Asserts that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LE(a, b); // pass! @@ -122,7 +230,7 @@ Asserts that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GT(a, b); // pass! @@ -136,7 +244,7 @@ Asserts that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GE(a, b); // pass! @@ -153,7 +261,7 @@ Expects that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; EXPECT_TRUE(i); // pass! EXPECT_TRUE(42); // pass! @@ -164,7 +272,7 @@ Expects that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; EXPECT_FALSE(i); // pass! EXPECT_FALSE(1); // fail! @@ -174,7 +282,7 @@ Expects that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; EXPECT_EQ(a, b); // pass! @@ -188,7 +296,7 @@ Expects that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_NE(a, b); // pass! @@ -202,7 +310,7 @@ Expects that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LT(a, b); // pass! @@ -216,7 +324,7 @@ Expects that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LE(a, b); // pass! @@ -233,7 +341,7 @@ Expects that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GT(a, b); // pass! @@ -247,7 +355,7 @@ Expects that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GE(a, b); // pass! diff --git a/test/test.c b/test/test.c index 5c4eb36..74c2327 100644 --- a/test/test.c +++ b/test/test.c @@ -26,10 +26,9 @@ #include "utest.h" #ifdef _MSC_VER -#pragma warning(push) - // disable 'conditional expression is constant' - our examples below use this! #pragma warning(disable : 4127) +#pragma #endif UTEST(c, ASSERT_TRUE) { ASSERT_TRUE(1); } @@ -84,25 +83,52 @@ UTEST(c, EXPECT_STRNE) { EXPECT_STRNE("foo", "bar"); } -struct MyTest { +struct MyTestF { int foo; }; -UTEST_F_SETUP(MyTest) { - ASSERT_EQ(0, fixture->foo); - fixture->foo = 42; +UTEST_F_SETUP(MyTestF) { + ASSERT_EQ(0, utest_fixture->foo); + utest_fixture->foo = 42; } -UTEST_F_TEARDOWN(MyTest) { - ASSERT_EQ(13, fixture->foo); +UTEST_F_TEARDOWN(MyTestF) { + ASSERT_EQ(13, utest_fixture->foo); } -UTEST_F(MyTest, c) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, c) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; } -UTEST_F(MyTest, c2) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, c2) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; +} + +struct MyTestI { + size_t foo; + size_t bar; +}; + +UTEST_I_SETUP(MyTestI) { + ASSERT_EQ(0, utest_fixture->foo); + ASSERT_EQ(0, utest_fixture->bar); + utest_fixture->foo = 42; + utest_fixture->bar = utest_index; +} + +UTEST_I_TEARDOWN(MyTestI) { + ASSERT_EQ(13, utest_fixture->foo); + ASSERT_EQ(utest_index, utest_fixture->bar); +} + +UTEST_I(MyTestI, c, 2) { + ASSERT_GT(2, utest_fixture->bar); + utest_fixture->foo = 13; +} + +UTEST_I(MyTestI, c2, 128) { + ASSERT_GT(128, utest_fixture->bar); + utest_fixture->foo = 13; } diff --git a/README.md b/README.md index ca471f4..8a49bd2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,15 @@ The current supported compilers are gcc, clang and msvc. -The current tested compiler versions are gcc 4.8.2, clang 3.5 and MSVC 18.0.21005.1. +The current supported platforms are Linux, Mac OSX and Windows. + +## Command Line Options ## + +utest.h supports some command line options: + +* --help to output the help message +* --filter= will filter the test cases to run (useful for re-running one particular offending test case). +* --output= will output an xunit XML file with the test results (that Jenkins, travis-ci, and appveyor can parse for the test results). ## Design ## @@ -24,25 +32,125 @@ [==========] 1 test cases ran. [ PASSED ] 1 tests. +## UTEST_MAIN ## + +In one C or C++ file, you must call the macro UTEST_MAIN: + + UTEST_MAIN(); + +This will call into utest.h, instantiate all the testcases and run the unit test framework. + +Alternatively, if you want to write your own main and call into utest.h, you can instead, in one C or C++ file call: + + UTEST_STATE(); + +And then when you are ready to call into the utest.h framework do: + + int main(int argc, const char *const argv[]) { + // do your own thing + return utest_main(argc, argv); + } + +## Define a Testcase ## + To define a test case to run, you can do the following; #include "utest.h" - TESTCASE(foo, bar) { + UTEST(foo, bar) { ASSERT_TRUE(1); } -The TESTCASE macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. +The UTEST macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. + +## Define a Fixtured Testcase ## + +A fixtured testcase is one in which there is a struct that is instantiated that can be shared across multiple testcases. + + struct MyTestFixture { + char c; + int i; + float f; + }; + + UTEST_F_SETUP(MyTestFixture) { + utest_fixture->c = 'a'; + utest_fixture->i = 42; + utest_fixture->f = 3.14f; + + // we can even assert and expect in setup! + ASSERT_EQ(42, utest_fixture->i); + EXPECT_TRUE(true); + } + + UTEST_F_TEARDOWN(MyTestFixture) { + // and also assert and expect in teardown! + ASSERT_EQ(13, utest_fixture->i); + } + + UTEST_F(MyTestFixture, a) { + utest_fixture->i = 13; + // teardown will succeed because i is 13... + } + + UTEST_F(MyTestFixture, b) { + utest_fixture->i = 83; + // teardown will fail because i is not 13! + } + +Some things to note that were demonstrated above: +* We have this new implicit variable within our macros - utest_fixture. This is a pointer to the struct you decidedw as your fixture (so MyTestFixture in the above code). +* Instead of specifying a testcase set (like we do with the UTEST macro), we instead specify the name of the fixture struct we are use. +* Every fixture has to have a UTEST_F_SETUP and UTEST_F_TEARDOWN macro - even if they do nothing in the body of them. +* Multiple testcases (UTEST_F's) can use the same fixture. +* You can use EXPECT_* and ASSERT_* macros within the body of both the fixture's setup and teardown macros. + +## Define an Indexed Testcase ## + +Sometimes you want to use the same fixture _and_ testcase repeatedly, but prehaps subtly change one variable within. This is where indexed testcases come in. + + struct MyTestIndexedFixture{ + bool x; + bool y; + }; + + UTEST_I_SETUP(MyTestIndexedFixture) { + if (utest_index < 30) { + utest_fixture->x = utest_index & 1; + utest_fixture->y = (utest_index + 1) & 1; + } + } + + UTEST_I_TEARDOWN(MyTestIndexedFixture) { + EXPECT_LE(0, utest_index); + } + + UTEST_I(MyTestIndexedFixture, a, 2) { + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + + UTEST_I(MyTestIndexedFixture, b, 42) { + // this will fail when the index is >= 30 + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + +Note: +* We use UTEST_I_* as the prefix for the setup and teardown functions now. +* We use UTEST_I to declare the testcases. +* We have access to a new variable utest_index in our setup and teardown functions, that we can use to slightly vary our fixture. +* We provide a number as the third parameter of the UTEST_I macro - this is the number of times we should run the test case for that index. It must be a literal. + +## Testing Macros ## Matching what googletest has, we provide two variants of each of the error checking conditions - ASSERT's and EXPECT's. If an ASSERT fails, the test case will cease execution, and utest.h will continue with the next test case to be run. If an EXPECT fails, the remainder of the test case will still be executed, allowing for further checks to be carried out. -We currently provide the following macros to be used within TESTCASE's. +We currently provide the following macros to be used within UTEST's. ### ASSERT_TRUE(x) ### Asserts that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; ASSERT_TRUE(i); // pass! ASSERT_TRUE(42); // pass! @@ -53,7 +161,7 @@ Asserts that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; ASSERT_FALSE(i); // pass! ASSERT_FALSE(1); // fail! @@ -63,7 +171,7 @@ Asserts that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; ASSERT_EQ(a, b); // pass! @@ -77,7 +185,7 @@ Asserts that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_NE(a, b); // pass! @@ -91,7 +199,7 @@ Asserts that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LT(a, b); // pass! @@ -105,7 +213,7 @@ Asserts that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LE(a, b); // pass! @@ -122,7 +230,7 @@ Asserts that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GT(a, b); // pass! @@ -136,7 +244,7 @@ Asserts that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GE(a, b); // pass! @@ -153,7 +261,7 @@ Expects that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; EXPECT_TRUE(i); // pass! EXPECT_TRUE(42); // pass! @@ -164,7 +272,7 @@ Expects that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; EXPECT_FALSE(i); // pass! EXPECT_FALSE(1); // fail! @@ -174,7 +282,7 @@ Expects that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; EXPECT_EQ(a, b); // pass! @@ -188,7 +296,7 @@ Expects that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_NE(a, b); // pass! @@ -202,7 +310,7 @@ Expects that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LT(a, b); // pass! @@ -216,7 +324,7 @@ Expects that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LE(a, b); // pass! @@ -233,7 +341,7 @@ Expects that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GT(a, b); // pass! @@ -247,7 +355,7 @@ Expects that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GE(a, b); // pass! diff --git a/test/test.c b/test/test.c index 5c4eb36..74c2327 100644 --- a/test/test.c +++ b/test/test.c @@ -26,10 +26,9 @@ #include "utest.h" #ifdef _MSC_VER -#pragma warning(push) - // disable 'conditional expression is constant' - our examples below use this! #pragma warning(disable : 4127) +#pragma #endif UTEST(c, ASSERT_TRUE) { ASSERT_TRUE(1); } @@ -84,25 +83,52 @@ UTEST(c, EXPECT_STRNE) { EXPECT_STRNE("foo", "bar"); } -struct MyTest { +struct MyTestF { int foo; }; -UTEST_F_SETUP(MyTest) { - ASSERT_EQ(0, fixture->foo); - fixture->foo = 42; +UTEST_F_SETUP(MyTestF) { + ASSERT_EQ(0, utest_fixture->foo); + utest_fixture->foo = 42; } -UTEST_F_TEARDOWN(MyTest) { - ASSERT_EQ(13, fixture->foo); +UTEST_F_TEARDOWN(MyTestF) { + ASSERT_EQ(13, utest_fixture->foo); } -UTEST_F(MyTest, c) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, c) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; } -UTEST_F(MyTest, c2) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, c2) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; +} + +struct MyTestI { + size_t foo; + size_t bar; +}; + +UTEST_I_SETUP(MyTestI) { + ASSERT_EQ(0, utest_fixture->foo); + ASSERT_EQ(0, utest_fixture->bar); + utest_fixture->foo = 42; + utest_fixture->bar = utest_index; +} + +UTEST_I_TEARDOWN(MyTestI) { + ASSERT_EQ(13, utest_fixture->foo); + ASSERT_EQ(utest_index, utest_fixture->bar); +} + +UTEST_I(MyTestI, c, 2) { + ASSERT_GT(2, utest_fixture->bar); + utest_fixture->foo = 13; +} + +UTEST_I(MyTestI, c2, 128) { + ASSERT_GT(128, utest_fixture->bar); + utest_fixture->foo = 13; } diff --git a/test/test.cpp b/test/test.cpp index 46e5785..59aff0a 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -84,25 +84,52 @@ UTEST(c, EXPECT_STRNE) { EXPECT_STRNE("foo", "bar"); } -struct MyTest { +struct MyTestF { int foo; }; -UTEST_F_SETUP(MyTest) { - ASSERT_EQ(0, fixture->foo); - fixture->foo = 42; +UTEST_F_SETUP(MyTestF) { + ASSERT_EQ(0, utest_fixture->foo); + utest_fixture->foo = 42; } -UTEST_F_TEARDOWN(MyTest) { - ASSERT_EQ(13, fixture->foo); +UTEST_F_TEARDOWN(MyTestF) { + ASSERT_EQ(13, utest_fixture->foo); } -UTEST_F(MyTest, cpp) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, cpp) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; } -UTEST_F(MyTest, cpp2) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, cpp2) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; +} + +struct MyTestI { + size_t foo; + size_t bar; +}; + +UTEST_I_SETUP(MyTestI) { + ASSERT_EQ(0, utest_fixture->foo); + ASSERT_EQ(0, utest_fixture->bar); + utest_fixture->foo = 42; + utest_fixture->bar = utest_index; +} + +UTEST_I_TEARDOWN(MyTestI) { + ASSERT_EQ(13, utest_fixture->foo); + ASSERT_EQ(utest_index, utest_fixture->bar); +} + +UTEST_I(MyTestI, cpp, 2) { + ASSERT_GT(2, utest_fixture->bar); + utest_fixture->foo = 13; +} + +UTEST_I(MyTestI, cpp2, 128) { + ASSERT_GT(128, utest_fixture->bar); + utest_fixture->foo = 13; } diff --git a/README.md b/README.md index ca471f4..8a49bd2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,15 @@ The current supported compilers are gcc, clang and msvc. -The current tested compiler versions are gcc 4.8.2, clang 3.5 and MSVC 18.0.21005.1. +The current supported platforms are Linux, Mac OSX and Windows. + +## Command Line Options ## + +utest.h supports some command line options: + +* --help to output the help message +* --filter= will filter the test cases to run (useful for re-running one particular offending test case). +* --output= will output an xunit XML file with the test results (that Jenkins, travis-ci, and appveyor can parse for the test results). ## Design ## @@ -24,25 +32,125 @@ [==========] 1 test cases ran. [ PASSED ] 1 tests. +## UTEST_MAIN ## + +In one C or C++ file, you must call the macro UTEST_MAIN: + + UTEST_MAIN(); + +This will call into utest.h, instantiate all the testcases and run the unit test framework. + +Alternatively, if you want to write your own main and call into utest.h, you can instead, in one C or C++ file call: + + UTEST_STATE(); + +And then when you are ready to call into the utest.h framework do: + + int main(int argc, const char *const argv[]) { + // do your own thing + return utest_main(argc, argv); + } + +## Define a Testcase ## + To define a test case to run, you can do the following; #include "utest.h" - TESTCASE(foo, bar) { + UTEST(foo, bar) { ASSERT_TRUE(1); } -The TESTCASE macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. +The UTEST macro takes two parameters - the first being the set that the test case belongs to, the second being the name of the test. This allows tests to be grouped for conveience. + +## Define a Fixtured Testcase ## + +A fixtured testcase is one in which there is a struct that is instantiated that can be shared across multiple testcases. + + struct MyTestFixture { + char c; + int i; + float f; + }; + + UTEST_F_SETUP(MyTestFixture) { + utest_fixture->c = 'a'; + utest_fixture->i = 42; + utest_fixture->f = 3.14f; + + // we can even assert and expect in setup! + ASSERT_EQ(42, utest_fixture->i); + EXPECT_TRUE(true); + } + + UTEST_F_TEARDOWN(MyTestFixture) { + // and also assert and expect in teardown! + ASSERT_EQ(13, utest_fixture->i); + } + + UTEST_F(MyTestFixture, a) { + utest_fixture->i = 13; + // teardown will succeed because i is 13... + } + + UTEST_F(MyTestFixture, b) { + utest_fixture->i = 83; + // teardown will fail because i is not 13! + } + +Some things to note that were demonstrated above: +* We have this new implicit variable within our macros - utest_fixture. This is a pointer to the struct you decidedw as your fixture (so MyTestFixture in the above code). +* Instead of specifying a testcase set (like we do with the UTEST macro), we instead specify the name of the fixture struct we are use. +* Every fixture has to have a UTEST_F_SETUP and UTEST_F_TEARDOWN macro - even if they do nothing in the body of them. +* Multiple testcases (UTEST_F's) can use the same fixture. +* You can use EXPECT_* and ASSERT_* macros within the body of both the fixture's setup and teardown macros. + +## Define an Indexed Testcase ## + +Sometimes you want to use the same fixture _and_ testcase repeatedly, but prehaps subtly change one variable within. This is where indexed testcases come in. + + struct MyTestIndexedFixture{ + bool x; + bool y; + }; + + UTEST_I_SETUP(MyTestIndexedFixture) { + if (utest_index < 30) { + utest_fixture->x = utest_index & 1; + utest_fixture->y = (utest_index + 1) & 1; + } + } + + UTEST_I_TEARDOWN(MyTestIndexedFixture) { + EXPECT_LE(0, utest_index); + } + + UTEST_I(MyTestIndexedFixture, a, 2) { + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + + UTEST_I(MyTestIndexedFixture, b, 42) { + // this will fail when the index is >= 30 + ASSERT_TRUE(utest_fixture->x | utest_fixture->y); + } + +Note: +* We use UTEST_I_* as the prefix for the setup and teardown functions now. +* We use UTEST_I to declare the testcases. +* We have access to a new variable utest_index in our setup and teardown functions, that we can use to slightly vary our fixture. +* We provide a number as the third parameter of the UTEST_I macro - this is the number of times we should run the test case for that index. It must be a literal. + +## Testing Macros ## Matching what googletest has, we provide two variants of each of the error checking conditions - ASSERT's and EXPECT's. If an ASSERT fails, the test case will cease execution, and utest.h will continue with the next test case to be run. If an EXPECT fails, the remainder of the test case will still be executed, allowing for further checks to be carried out. -We currently provide the following macros to be used within TESTCASE's. +We currently provide the following macros to be used within UTEST's. ### ASSERT_TRUE(x) ### Asserts that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; ASSERT_TRUE(i); // pass! ASSERT_TRUE(42); // pass! @@ -53,7 +161,7 @@ Asserts that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; ASSERT_FALSE(i); // pass! ASSERT_FALSE(1); // fail! @@ -63,7 +171,7 @@ Asserts that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; ASSERT_EQ(a, b); // pass! @@ -77,7 +185,7 @@ Asserts that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_NE(a, b); // pass! @@ -91,7 +199,7 @@ Asserts that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LT(a, b); // pass! @@ -105,7 +213,7 @@ Asserts that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; ASSERT_LE(a, b); // pass! @@ -122,7 +230,7 @@ Asserts that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GT(a, b); // pass! @@ -136,7 +244,7 @@ Asserts that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; ASSERT_GE(a, b); // pass! @@ -153,7 +261,7 @@ Expects that x evaluates to true (EG. non-zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 1; EXPECT_TRUE(i); // pass! EXPECT_TRUE(42); // pass! @@ -164,7 +272,7 @@ Expects that x evaluates to false (EG. zero). - TESTCASE(foo, bar) { + UTEST(foo, bar) { int i = 0; EXPECT_FALSE(i); // pass! EXPECT_FALSE(1); // fail! @@ -174,7 +282,7 @@ Expects that x and y are equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 42; EXPECT_EQ(a, b); // pass! @@ -188,7 +296,7 @@ Expects that x and y are not equal. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_NE(a, b); // pass! @@ -202,7 +310,7 @@ Expects that x is less than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LT(a, b); // pass! @@ -216,7 +324,7 @@ Expects that x is less than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 13; int b = 42; EXPECT_LE(a, b); // pass! @@ -233,7 +341,7 @@ Expects that x is greater than y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GT(a, b); // pass! @@ -247,7 +355,7 @@ Expects that x is greater than or equal to y. - TESTCASE(foo, bar) { + UTEST(foo, bar) { int a = 42; int b = 13; EXPECT_GE(a, b); // pass! diff --git a/test/test.c b/test/test.c index 5c4eb36..74c2327 100644 --- a/test/test.c +++ b/test/test.c @@ -26,10 +26,9 @@ #include "utest.h" #ifdef _MSC_VER -#pragma warning(push) - // disable 'conditional expression is constant' - our examples below use this! #pragma warning(disable : 4127) +#pragma #endif UTEST(c, ASSERT_TRUE) { ASSERT_TRUE(1); } @@ -84,25 +83,52 @@ UTEST(c, EXPECT_STRNE) { EXPECT_STRNE("foo", "bar"); } -struct MyTest { +struct MyTestF { int foo; }; -UTEST_F_SETUP(MyTest) { - ASSERT_EQ(0, fixture->foo); - fixture->foo = 42; +UTEST_F_SETUP(MyTestF) { + ASSERT_EQ(0, utest_fixture->foo); + utest_fixture->foo = 42; } -UTEST_F_TEARDOWN(MyTest) { - ASSERT_EQ(13, fixture->foo); +UTEST_F_TEARDOWN(MyTestF) { + ASSERT_EQ(13, utest_fixture->foo); } -UTEST_F(MyTest, c) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, c) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; } -UTEST_F(MyTest, c2) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, c2) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; +} + +struct MyTestI { + size_t foo; + size_t bar; +}; + +UTEST_I_SETUP(MyTestI) { + ASSERT_EQ(0, utest_fixture->foo); + ASSERT_EQ(0, utest_fixture->bar); + utest_fixture->foo = 42; + utest_fixture->bar = utest_index; +} + +UTEST_I_TEARDOWN(MyTestI) { + ASSERT_EQ(13, utest_fixture->foo); + ASSERT_EQ(utest_index, utest_fixture->bar); +} + +UTEST_I(MyTestI, c, 2) { + ASSERT_GT(2, utest_fixture->bar); + utest_fixture->foo = 13; +} + +UTEST_I(MyTestI, c2, 128) { + ASSERT_GT(128, utest_fixture->bar); + utest_fixture->foo = 13; } diff --git a/test/test.cpp b/test/test.cpp index 46e5785..59aff0a 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -84,25 +84,52 @@ UTEST(c, EXPECT_STRNE) { EXPECT_STRNE("foo", "bar"); } -struct MyTest { +struct MyTestF { int foo; }; -UTEST_F_SETUP(MyTest) { - ASSERT_EQ(0, fixture->foo); - fixture->foo = 42; +UTEST_F_SETUP(MyTestF) { + ASSERT_EQ(0, utest_fixture->foo); + utest_fixture->foo = 42; } -UTEST_F_TEARDOWN(MyTest) { - ASSERT_EQ(13, fixture->foo); +UTEST_F_TEARDOWN(MyTestF) { + ASSERT_EQ(13, utest_fixture->foo); } -UTEST_F(MyTest, cpp) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, cpp) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; } -UTEST_F(MyTest, cpp2) { - ASSERT_EQ(42, fixture->foo); - fixture->foo = 13; +UTEST_F(MyTestF, cpp2) { + ASSERT_EQ(42, utest_fixture->foo); + utest_fixture->foo = 13; +} + +struct MyTestI { + size_t foo; + size_t bar; +}; + +UTEST_I_SETUP(MyTestI) { + ASSERT_EQ(0, utest_fixture->foo); + ASSERT_EQ(0, utest_fixture->bar); + utest_fixture->foo = 42; + utest_fixture->bar = utest_index; +} + +UTEST_I_TEARDOWN(MyTestI) { + ASSERT_EQ(13, utest_fixture->foo); + ASSERT_EQ(utest_index, utest_fixture->bar); +} + +UTEST_I(MyTestI, cpp, 2) { + ASSERT_GT(2, utest_fixture->bar); + utest_fixture->foo = 13; +} + +UTEST_I(MyTestI, cpp2, 128) { + ASSERT_GT(128, utest_fixture->bar); + utest_fixture->foo = 13; } diff --git a/utest.h b/utest.h index c385c4b..20a98d5 100644 --- a/utest.h +++ b/utest.h @@ -135,24 +135,53 @@ #endif } -typedef void (*utest_testcase_t)(int *); +typedef void (*utest_testcase_t)(int *, size_t); struct utest_test_state_s { utest_testcase_t func; - const char *name; + size_t index; + char *name; }; struct utest_state_s { struct utest_test_state_s *tests; size_t tests_length; + FILE *output; }; +// extern to the global state utest needs to execute +UTEST_EXTERN struct utest_state_s utest_state; + #if defined(_MSC_VER) #define UTEST_WEAK __forceinline #else #define UTEST_WEAK __attribute__((weak)) #endif +#if defined(_MSC_VER) +#define UTEST_UNUSED +#else +#define UTEST_UNUSED __attribute__((unused)) +#endif + +#define UTEST_PRINTF0(FORMAT) \ + if (utest_state.output) { \ + fprintf(utest_state.output, FORMAT); \ + } \ + printf(FORMAT) + +#define UTEST_PRINTF1(FORMAT, P0) \ + if (utest_state.output) { \ + fprintf(utest_state.output, FORMAT, P0); \ + } \ + printf(FORMAT, P0) + +#define UTEST_PRINTF2(FORMAT, P0, P1) \ + if (utest_state.output) { \ + fprintf(utest_state.output, FORMAT, P0, P1); \ + } \ + printf(FORMAT, P0, P1) + #if defined(__cplusplus) // if we are using c++ we can use overloaded methods (its in the language) #define UTEST_OVERLOADABLE @@ -164,37 +193,37 @@ #if defined(UTEST_OVERLOADABLE) UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f) { - printf("%f", UTEST_CAST(double, f)); + UTEST_PRINTF1("%f", UTEST_CAST(double, f)); } UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d) { - printf("%f", d); + UTEST_PRINTF1("%f", d); } UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d) { - printf("%Lf", d); + UTEST_PRINTF1("%Lf", d); } UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i) { - printf("%d", i); + UTEST_PRINTF1("%d", i); } UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i) { - printf("%u", i); + UTEST_PRINTF1("%u", i); } UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i) { - printf("%ld", i); + UTEST_PRINTF1("%ld", i); } UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i) { - printf("%lu", i); + UTEST_PRINTF1("%lu", i); } // long long is a c++11 extension @@ -202,40 +231,40 @@ #if !defined(__cplusplus) UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i) { - printf("%lld", i); + UTEST_PRINTF1("%lld", i); } UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i); UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i) { - printf("%llu", i); + UTEST_PRINTF1("%llu", i); } #endif #else // we don't have the ability to print the values we got, so we create a macro to // tell our users we can't do anything fancy -#define utest_type_printer(...) printf("undef") +#define utest_type_printer(...) UTEST_PRINTF0("undef") #endif #define UTEST_EXPECT(x, y, cond) \ if (!((x)cond(y))) { \ - printf("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF2("%s:%u: Failure\n", __FILE__, __LINE__); \ *utest_result = 1; \ } #define EXPECT_TRUE(x) \ if (!(x)) { \ - printf("%s:%u: Failure\n", __FILE__, __LINE__); \ - printf(" Expected : true\n"); \ - printf(" Actual : %s\n", (x) ? "true" : "false"); \ + UTEST_PRINTF2("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF0(" Expected : true\n"); \ + UTEST_PRINTF1(" Actual : %s\n", (x) ? "true" : "false"); \ *utest_result = 1; \ } #define EXPECT_FALSE(x) \ if (x) { \ - printf("%s:%u: Failure\n", __FILE__, __LINE__); \ - printf(" Expected : false\n"); \ - printf(" Actual : %s\n", (x) ? "true" : "false"); \ + UTEST_PRINTF2("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF0(" Expected : false\n"); \ + UTEST_PRINTF1(" Actual : %s\n", (x) ? "true" : "false"); \ *utest_result = 1; \ } @@ -248,17 +277,17 @@ #define EXPECT_STREQ(x, y) \ if (0 != strcmp(x, y)) { \ - printf("%s:%u: Failure\n", __FILE__, __LINE__); \ - printf(" Expected : \"%s\"\n", x); \ - printf(" Actual : \"%s\"\n", y); \ + UTEST_PRINTF2("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF1(" Expected : \"%s\"\n", x); \ + UTEST_PRINTF1(" Actual : \"%s\"\n", y); \ *utest_result = 1; \ } #define EXPECT_STRNE(x, y) \ if (0 == strcmp(x, y)) { \ - printf("%s:%u: Failure\n", __FILE__, __LINE__); \ - printf(" Expected : \"%s\"\n", x); \ - printf(" Actual : \"%s\"\n", y); \ + UTEST_PRINTF2("%s:%u: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF1(" Expected : \"%s\"\n", x); \ + UTEST_PRINTF1(" Actual : \"%s\"\n", y); \ *utest_result = 1; \ } @@ -301,55 +330,104 @@ #define UTEST(SET, NAME) \ UTEST_EXTERN struct utest_state_s utest_state; \ - static void utest_run_##SET##_##NAME(int *utest_result); \ + static void utest_run_##SET##_##NAME(int *utest_result, size_t); \ UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \ const size_t index = utest_state.tests_length++; \ + const char *name_part = #SET "." #NAME; \ + char *name = UTEST_PTR_CAST(char *, malloc(strlen(name_part))); \ utest_state.tests = \ UTEST_PTR_CAST(struct utest_test_state_s *, \ realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ sizeof(struct utest_test_state_s) * \ utest_state.tests_length)); \ utest_state.tests[index].func = &utest_run_##SET##_##NAME; \ - utest_state.tests[index].name = #SET "." #NAME; \ + utest_state.tests[index].name = name; \ + sprintf(name, "%s", name_part); \ } \ - void utest_run_##SET##_##NAME(int *utest_result) + void utest_run_##SET##_##NAME(int *utest_result, \ + UTEST_UNUSED size_t utest_index) #define UTEST_F_SETUP(FIXTURE) \ - static void utest_setup_##FIXTURE(int *utest_result, struct FIXTURE *fixture) + static void utest_f_setup_##FIXTURE(int *utest_result, \ + struct FIXTURE *utest_fixture) #define UTEST_F_TEARDOWN(FIXTURE) \ - static void utest_teardown_##FIXTURE(int *utest_result, \ - struct FIXTURE *fixture) + static void utest_f_teardown_##FIXTURE(int *utest_result, \ + struct FIXTURE *utest_fixture) #define UTEST_F(FIXTURE, NAME) \ UTEST_EXTERN struct utest_state_s utest_state; \ static void utest_run_##FIXTURE##_##NAME(int *, struct FIXTURE *); \ - static void utest_fixture_##FIXTURE##_##NAME(int *utest_result) { \ - struct FIXTURE fixture = {0}; \ - utest_setup_##FIXTURE(utest_result, &fixture); \ + static void utest_f_##FIXTURE##_##NAME(int *utest_result, \ + UTEST_UNUSED size_t utest_index) { \ + struct FIXTURE fixture; \ + memset(&fixture, 0, sizeof(fixture)); \ + utest_f_setup_##FIXTURE(utest_result, &fixture); \ if (0 != *utest_result) { \ return; \ } \ utest_run_##FIXTURE##_##NAME(utest_result, &fixture); \ - utest_teardown_##FIXTURE(utest_result, &fixture); \ + utest_f_teardown_##FIXTURE(utest_result, &fixture); \ } \ UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \ const size_t index = utest_state.tests_length++; \ + const char *name_part = #FIXTURE "." #NAME; \ + char *name = UTEST_PTR_CAST(char *, malloc(strlen(name_part))); \ utest_state.tests = \ UTEST_PTR_CAST(struct utest_test_state_s *, \ realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ sizeof(struct utest_test_state_s) * \ utest_state.tests_length)); \ - utest_state.tests[index].func = &utest_fixture_##FIXTURE##_##NAME; \ - utest_state.tests[index].name = #FIXTURE "." #NAME; \ + utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \ + utest_state.tests[index].name = name; \ + sprintf(name, "%s", name_part); \ } \ - void utest_run_##FIXTURE##_##NAME(int *utest_result, struct FIXTURE *fixture) + void utest_run_##FIXTURE##_##NAME(int *utest_result, \ + struct FIXTURE *utest_fixture) -// extern to the global state utest needs to execute -UTEST_EXTERN struct utest_state_s utest_state; +#define UTEST_I_SETUP(FIXTURE) \ + static void utest_i_setup_##FIXTURE( \ + int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) -UTEST_WEAK int utest_should_filter_test(const char *filter, - const char *testcase); +#define UTEST_I_TEARDOWN(FIXTURE) \ + static void utest_i_teardown_##FIXTURE( \ + int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) + +#define UTEST_I(FIXTURE, NAME, INDEX) \ + UTEST_EXTERN struct utest_state_s utest_state; \ + static void utest_run_##FIXTURE##_##NAME##_##INDEX(int *, struct FIXTURE *); \ + static void utest_i_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ + size_t index) { \ + struct FIXTURE fixture; \ + memset(&fixture, 0, sizeof(fixture)); \ + utest_i_setup_##FIXTURE(utest_result, &fixture, index); \ + if (0 != *utest_result) { \ + return; \ + } \ + utest_run_##FIXTURE##_##NAME##_##INDEX(utest_result, &fixture); \ + utest_i_teardown_##FIXTURE(utest_result, &fixture, index); \ + } \ + UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME##_##INDEX) { \ + for (size_t i = 0; i < (INDEX); i++) { \ + const size_t index = utest_state.tests_length++; \ + const char *name_part = #FIXTURE "." #NAME; \ + char *name = UTEST_PTR_CAST(char *, malloc(strlen(name_part) + 32)); \ + utest_state.tests = \ + UTEST_PTR_CAST(struct utest_test_state_s *, \ + realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ + sizeof(struct utest_test_state_s) * \ + utest_state.tests_length)); \ + utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \ + utest_state.tests[index].index = i; \ + utest_state.tests[index].name = name; \ + sprintf(name, "%s/%" UTEST_PRIu64, name_part, UTEST_CAST(uint64_t, i)); \ + } \ + } \ + void utest_run_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ + struct FIXTURE *utest_fixture) + +UTEST_WEAK +int utest_should_filter_test(const char *filter, const char *testcase); UTEST_WEAK int utest_should_filter_test(const char *filter, const char *testcase) { if (filter) { @@ -425,11 +503,24 @@ // loop through all arguments looking for our options for (index = 1; index < UTEST_CAST(size_t, argc); index++) { + const char help_str[] = "--help"; const char filter_str[] = "--filter="; + const char output_str[] = "--output="; - if (0 < strcmp(argv[index], filter_str)) { + if (0 == strncmp(argv[index], help_str, strlen(help_str))) { + printf("utest.h - the single file unit testing solution for C/C++!\n" + "Command line Options:\n" + " --help Show this message and exit.\n" + " --filter= Filter the test cases to run (EG. MyTest*.a " + "would run MyTestCase.a but not MyTestCase.b).\n" + " --output= Output an xunit XML file to the file " + "specified in .\n"); + goto cleanup; + } else if (0 == strncmp(argv[index], filter_str, strlen(filter_str))) { // user wants to filter what test cases run! filter = argv[index] + strlen(filter_str); + } else if (0 == strncmp(argv[index], output_str, strlen(output_str))) { + utest_state.output = fopen(argv[index] + strlen(output_str), "w+"); } } @@ -444,6 +535,12 @@ printf("\033[32m[==========]\033[0m Running %" UTEST_PRIu64 " test cases.\n", UTEST_CAST(uint64_t, ran_tests)); + if (utest_state.output) { + fprintf(utest_state.output, "\n"); + fprintf(utest_state.output, "\n", UTEST_CAST(uint64_t, ran_tests)); + fprintf(utest_state.output, "\n", UTEST_CAST(uint64_t, ran_tests)); + } + for (index = 0; index < utest_state.tests_length; index++) { int result = 0; int64_t ns = 0; @@ -453,9 +550,19 @@ } printf("\033[32m[ RUN ]\033[0m %s\n", utest_state.tests[index].name); + + if (utest_state.output) { + fprintf(utest_state.output, "", utest_state.tests[index].name); + } + ns = utest_ns(); - utest_state.tests[index].func(&result); + utest_state.tests[index].func(&result, utest_state.tests[index].index); ns = utest_ns() - ns; + + if (utest_state.output) { + fprintf(utest_state.output, "\n"); + } + if (0 != result) { const size_t failed_testcase_index = failed_testcases_length++; failed_testcases = UTEST_PTR_CAST( @@ -483,8 +590,23 @@ utest_state.tests[failed_testcases[index]].name); } } + + if (utest_state.output) { + fprintf(utest_state.output, "\n\n"); + } + +cleanup: + for (index = 0; index < utest_state.tests_length; index++) { + free(UTEST_PTR_CAST(void *, utest_state.tests[index].name)); + } + free(UTEST_PTR_CAST(void *, failed_testcases)); free(UTEST_PTR_CAST(void *, utest_state.tests)); + + if (utest_state.output) { + fclose(utest_state.output); + } + return UTEST_CAST(int, failed); } @@ -492,7 +614,7 @@ // the data we need to run utest. This macro allows the user to declare the // data without having to use the UTEST_MAIN macro, thus allowing them to write // their own main() function. -#define UTEST_STATE() struct utest_state_s utest_state +#define UTEST_STATE() struct utest_state_s utest_state = {0, 0, 0} // define a main() function to call into utest.h and start executing tests! A // user can optionally not use this macro, and instead define their own main()