🧪 single header unit testing framework for C and C++

🧪 utest.h

Actions Status Build status Sponsor

A simple one header solution to unit testing for C/C++.

Usage

Just #include "utest.h" in your code!

The current supported platforms are Linux, macOS and Windows.

The current supported compilers are gcc, clang, MSVC's cl.exe, and clang-cl.exe.

Command Line Options

utest.h supports some command line options:

  • --help to output the help message
  • --filter=<filter> will filter the test cases to run (useful for re-running one particular offending test case).
  • --list-tests will list testnames, one per line. Output names can be passed to --filter.
  • --output=<output> will output an xunit XML file with the test results (that Jenkins, travis-ci, and appveyor can parse for the test results).

Design

UTest is a single header library to enable all the fun of unit testing in C and C++. The library has been designed to provide an output similar to Google's googletest framework:

[==========] Running 1 test cases.
[ RUN      ] foo.bar
[       OK ] foo.bar (631ns)
[==========] 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"

UTEST(foo, bar) {
  ASSERT_TRUE(1);
}

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 convenience.

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 decided 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 using.
  • Every fixture has to have a UTEST_F_SETUP and UTEST_F_TEARDOWN macro - even if they do nothing in the body.
  • 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 perhaps 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 - ASSERTs and EXPECTs. 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 UTESTs:

ASSERT_TRUE(x)

Asserts that x evaluates to true (EG. non-zero).

UTEST(foo, bar) {
  int i = 1;
  ASSERT_TRUE(i);  // pass!
  ASSERT_TRUE(42); // pass!
  ASSERT_TRUE(0);  // fail!
}

ASSERT_FALSE(x)

Asserts that x evaluates to false (EG. zero).

UTEST(foo, bar) {
  int i = 0;
  ASSERT_FALSE(i); // pass!
  ASSERT_FALSE(1); // fail!
}

ASSERT_EQ(x, y)

Asserts that x and y are equal.

UTEST(foo, bar) {
  int a = 42;
  int b = 42;
  ASSERT_EQ(a, b);     // pass!
  ASSERT_EQ(a, 42);    // pass!
  ASSERT_EQ(42, b);    // pass!
  ASSERT_EQ(42, 42);   // pass!
  ASSERT_EQ(a, b + 1); // fail!
}

ASSERT_NE(x, y)

Asserts that x and y are not equal.

UTEST(foo, bar) {
  int a = 42;
  int b = 13;
  ASSERT_NE(a, b);   // pass!
  ASSERT_NE(a, 27);  // pass!
  ASSERT_NE(69, b);  // pass!
  ASSERT_NE(42, 13); // pass!
  ASSERT_NE(a, 42);  // fail!
}

ASSERT_LT(x, y)

Asserts that x is less than y.

UTEST(foo, bar) {
  int a = 13;
  int b = 42;
  ASSERT_LT(a, b);   // pass!
  ASSERT_LT(a, 27);  // pass!
  ASSERT_LT(27, b);  // pass!
  ASSERT_LT(13, 42); // pass!
  ASSERT_LT(b, a);   // fail!
}

ASSERT_LE(x, y)

Asserts that x is less than or equal to y.

UTEST(foo, bar) {
  int a = 13;
  int b = 42;
  ASSERT_LE(a, b);   // pass!
  ASSERT_LE(a, 27);  // pass!
  ASSERT_LE(a, 13);  // pass!
  ASSERT_LE(27, b);  // pass!
  ASSERT_LE(42, b);  // pass!
  ASSERT_LE(13, 13); // pass!
  ASSERT_LE(13, 42); // pass!
  ASSERT_LE(b, a);   // fail!
}

ASSERT_GT(x, y)

Asserts that x is greater than y.

UTEST(foo, bar) {
  int a = 42;
  int b = 13;
  ASSERT_GT(a, b);   // pass!
  ASSERT_GT(a, 27);  // pass!
  ASSERT_GT(27, b);  // pass!
  ASSERT_GT(42, 13); // pass!
  ASSERT_GT(b, a);   // fail!
}

ASSERT_GE(x, y)

Asserts that x is greater than or equal to y.

UTEST(foo, bar) {
  int a = 42;
  int b = 13;
  ASSERT_GE(a, b);   // pass!
  ASSERT_GE(a, 27);  // pass!
  ASSERT_GE(a, 13);  // pass!
  ASSERT_GE(27, b);  // pass!
  ASSERT_GE(42, b);  // pass!
  ASSERT_GE(13, 13); // pass!
  ASSERT_GE(42, 13); // pass!
  ASSERT_GE(b, a);   // fail!
}

ASSERT_STREQ(x, y)

Asserts that the strings x and y are equal.

UTEST(foo, bar) {
  char* a = "foo";
  char* b = "bar";
  ASSERT_STREQ(a, a); // pass!
  ASSERT_STREQ(b, b); // pass!
  ASSERT_STREQ(a, b); // fail!
}

ASSERT_STRNE(x, y)

Asserts that the strings x and y are not equal.

UTEST(foo, bar) {
  char* a = "foo";
  char* b = "bar";
  ASSERT_STREQ(a, b); // pass!
  ASSERT_STREQ(a, a); // fail!
}

ASSERT_STRNEQ(x, y)

Asserts that the strings x and y are equal up to the length of the string x.

UTEST(foo, bar) {
  char* a = "foobar";
  char* b = "foo";
  ASSERT_STRNEQ(a, a); // pass!
  ASSERT_STRNEQ(b, b); // pass!
  ASSERT_STRNEQ(a, b); // pass!
}

ASSERT_STRNNE(x, y)

Asserts that the strings x and y are not equal up to the length of the string x.

UTEST(foo, bar) {
  char* a = "foobar";
  char* b = "bar";
  ASSERT_STRNNE(a, b); // pass!
  ASSERT_STRNNE(a, a); // fail!
}

EXPECT_TRUE(x)

Expects that x evaluates to true (i.e. non-zero).

UTEST(foo, bar) {
  int i = 1;
  EXPECT_TRUE(i);  // pass!
  EXPECT_TRUE(42); // pass!
  EXPECT_TRUE(0);  // fail!
}

EXPECT_FALSE(x)

Expects that x evaluates to false (i.e. zero).

UTEST(foo, bar) {
  int i = 0;
  EXPECT_FALSE(i); // pass!
  EXPECT_FALSE(1); // fail!
}

EXPECT_EQ(x, y)

Expects that x and y are equal.

UTEST(foo, bar) {
  int a = 42;
  int b = 42;
  EXPECT_EQ(a, b);     // pass!
  EXPECT_EQ(a, 42);    // pass!
  EXPECT_EQ(42, b);    // pass!
  EXPECT_EQ(42, 42);   // pass!
  EXPECT_EQ(a, b + 1); // fail!
}

EXPECT_NE(x, y)

Expects that x and y are not equal.

UTEST(foo, bar) {
  int a = 42;
  int b = 13;
  EXPECT_NE(a, b);   // pass!
  EXPECT_NE(a, 27);  // pass!
  EXPECT_NE(69, b);  // pass!
  EXPECT_NE(42, 13); // pass!
  EXPECT_NE(a, 42);  // fail!
}

EXPECT_LT(x, y)

Expects that x is less than y.

UTEST(foo, bar) {
  int a = 13;
  int b = 42;
  EXPECT_LT(a, b);   // pass!
  EXPECT_LT(a, 27);  // pass!
  EXPECT_LT(27, b);  // pass!
  EXPECT_LT(13, 42); // pass!
  EXPECT_LT(b, a);   // fail!
}

EXPECT_LE(x, y)

Expects that x is less than or equal to y.

UTEST(foo, bar) {
  int a = 13;
  int b = 42;
  EXPECT_LE(a, b);   // pass!
  EXPECT_LE(a, 27);  // pass!
  EXPECT_LE(a, 13);  // pass!
  EXPECT_LE(27, b);  // pass!
  EXPECT_LE(42, b);  // pass!
  EXPECT_LE(13, 13); // pass!
  EXPECT_LE(13, 42); // pass!
  EXPECT_LE(b, a);   // fail!
}

EXPECT_GT(x, y)

Expects that x is greater than y.

UTEST(foo, bar) {
  int a = 42;
  int b = 13;
  EXPECT_GT(a, b);   // pass!
  EXPECT_GT(a, 27);  // pass!
  EXPECT_GT(27, b);  // pass!
  EXPECT_GT(42, 13); // pass!
  EXPECT_GT(b, a);   // fail!
}

EXPECT_GT(x, y)

Expects that x is greater than or equal to y.

UTEST(foo, bar) {
  int a = 42;
  int b = 13;
  EXPECT_GE(a, b);   // pass!
  EXPECT_GE(a, 27);  // pass!
  EXPECT_GE(a, 13);  // pass!
  EXPECT_GE(27, b);  // pass!
  EXPECT_GE(42, b);  // pass!
  EXPECT_GE(13, 13); // pass!
  EXPECT_GE(42, 13); // pass!
  EXPECT_GE(b, a);   // fail!
}

EXPECT_STREQ(x, y)

Expects that the strings x and y are equal.

UTEST(foo, bar) {
  char* a = "foo";
  char* b = "bar";
  EXPECT_STREQ(a, a); // pass!
  EXPECT_STREQ(b, b); // pass!
  EXPECT_STREQ(a, b); // fail!
}

EXPECT_STRNE(x, y)

Expects that the strings x and y are not equal.

UTEST(foo, bar) {
  char* a = "foo";
  char* b = "bar";
  EXPECT_STRNE(a, b); // pass!
  EXPECT_STRNE(a, a); // fail!
}

EXPECT_STRNEQ(x, y)

Expects that the strings x and y are equal up to the length of the string x.

UTEST(foo, bar) {
  char* a = "foobar";
  char* b = "foo";
  EXPECT_STRNEQ(a, a); // pass!
  EXPECT_STRNEQ(b, b); // pass!
  EXPECT_STRNEQ(a, b); // pass!
}

EXPECT_STRNNE(x, y)

Expects that the strings x and y are not equal up to the length of the string x.

UTEST(foo, bar) {
  char* a = "foobar";
  char* b = "bar";
  EXPECT_STRNNE(a, b); // pass!
  EXPECT_STRNNE(a, a); // fail!
}

Types Supported for Checks

The library supports asserting on any builtin integer, floating-point, or pointer type.

License

This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to http://unlicense.org/

Owner
Neil Henning
Compiler Warlock on Burst @ Unity
Neil Henning
Comments
  • musl libc support

    musl libc support

    I'm using Alpine linux, a linux distribution based on musl libc instead of glibc, and i'm encountering a couple of compilation issues

    First this issue about the time.h header that is not included

    In file included from /home/simon/dev/utest.h/test/main.c:26:
    /home/simon/dev/utest.h/test/../utest.h: In function ā€˜utest_ns’:
    /home/simon/dev/utest.h/test/../utest.h:200:19: error: storage size of ā€˜ts’ isn’t known
      200 |   struct timespec ts;
          |                   ^~
    /home/simon/dev/utest.h/test/../utest.h:204:9: error: unknown type name ā€˜clockid_t’
      204 |   const clockid_t cid = CLOCK_REALTIME;
          |         ^~~~~~~~~
    /home/simon/dev/utest.h/test/../utest.h:204:25: error: ā€˜CLOCK_REALTIME’ undeclared (first use in this function)
      204 |   const clockid_t cid = CLOCK_REALTIME;
          |                         ^~~~~~~~~~~~~~
    /home/simon/dev/utest.h/test/../utest.h:204:25: note: each undeclared identifier is reported only once for each function it appears in
    /home/simon/dev/utest.h/test/../utest.h:208:11: error: ā€˜SYS_clock_gettime’ undeclared (first use in this function)
      208 |   syscall(SYS_clock_gettime, cid, &ts);
          |           ^~~~~~~~~~~~~~~~~
    /home/simon/dev/utest.h/test/../utest.h:200:19: error: unused variable ā€˜ts’ [-Werror=unused-variable]
      200 |   struct timespec ts;
          |                   ^~
    /home/simon/dev/utest.h/test/../utest.h:215:1: error: control reaches end of non-void function [-Werror=return-type]
      215 | }
          | ^
    

    Which is easily fixed by this patch

    diff --git a/utest.h b/utest.h
    index 7f2bcaa..5ade166 100644
    --- a/utest.h
    +++ b/utest.h
    @@ -101,6 +101,10 @@ typedef uint64_t utest_uint64_t;
     #include <sys/syscall.h>
     #include <unistd.h>
     #endif
    +#else /* non glibc platforms */
    +#include <time.h>
    +#include <sys/syscall.h>
    +#include <unistd.h>
     #endif
    
     #elif defined(__APPLE__)
    

    But then the real trouble begins

    [ 50%] Linking CXX executable utest_test_wpo
    /usr/bin/ld: cannot find -lgcc_
    

    This caused by the fact that the project is using the gnu standard instead of the regular one. Changing it causes another wave of compilation issues, mostly due to comments and other non-standard things that gnu89 has.

    [  6%] Building C object CMakeFiles/utest_test_wpo.dir/main.c.o
    /home/simon/dev/utest.h/test/main.c:1:1: error: C++ style comments are not allowed in ISO C90
        1 | // This is free and unencumbered software released into the public domain.
          | ^
    /home/simon/dev/utest.h/test/main.c:1:1: note: (this will be reported only once per input file)
    In file included from /home/simon/dev/utest.h/test/main.c:26:
    /home/simon/dev/utest.h/test/../utest.h:160:22: error: unknown type name ā€˜inline’
      160 | #define UTEST_INLINE inline
          |                      ^~~~~~
    /home/simon/dev/utest.h/test/../utest.h:195:8: note: in expansion of macro ā€˜UTEST_INLINE’
      195 | static UTEST_INLINE utest_int64_t utest_ns(void) {
          |        ^~~~~~~~~~~~
    /home/simon/dev/utest.h/test/../utest.h:195:35: error: expected ā€˜=’, ā€˜,’, ā€˜;’, ā€˜asm’ or ā€˜__attribute__’ before ā€˜utest_ns’
      195 | static UTEST_INLINE utest_int64_t utest_ns(void) {
          |                                   ^~~~~~~~
    /home/simon/dev/utest.h/test/../utest.h:798:21: error: expected ā€˜;’ before ā€˜int’
      798 | static UTEST_INLINE int utest_strncmp(const char *a, const char *b, size_t n) {
          |                     ^~~
    /home/simon/dev/utest.h/test/../utest.h:160:22: error: unknown type name ā€˜inline’
      160 | #define UTEST_INLINE inline
          |                      ^~~~~~
    /home/simon/dev/utest.h/test/../utest.h:813:8: note: in expansion of macro ā€˜UTEST_INLINE’
      813 | static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) {
          |        ^~~~~~~~~~~~
    /home/simon/dev/utest.h/test/../utest.h:813:26: error: expected ā€˜=’, ā€˜,’, ā€˜;’, ā€˜asm’ or ā€˜__attribute__’ before ā€˜*’ token
      813 | static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) {
          |                          ^
    /home/simon/dev/utest.h/test/../utest.h: In function ā€˜utest_main’:
    /home/simon/dev/utest.h/test/../utest.h:870:28: error: implicit declaration of function ā€˜utest_fopen’ [-Werror=implicit-function-declaration]
      870 |       utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+");
          |                            ^~~~~~~~~~~
    /home/simon/dev/utest.h/test/../utest.h:870:26: error: assignment to ā€˜FILE *’ from ā€˜int’ makes pointer from integer without a cast [-Werror=int-conversion]
      870 |       utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+");
          |                          ^
    /home/simon/dev/utest.h/test/../utest.h:917:10: error: implicit declaration of function ā€˜utest_ns’; did you mean ā€˜utest_main’? [-Werror=implicit-function-declaration]
      917 |     ns = utest_ns();
          |          ^~~~~~~~
          |          utest_main
    In file included from /home/simon/dev/utest.h/test/main.c:27:
    /home/simon/dev/utest.h/test/process.h: At top level:
    /home/simon/dev/utest.h/test/process.h:156:3: error: C++ style comments are not allowed in ISO C90
      156 |   // stdout and stderr are the same FILE.
          |   ^
    /home/simon/dev/utest.h/test/process.h:156:3: note: (this will be reported only once per input file)
    /home/simon/dev/utest.h/test/process.h: In function ā€˜process_create’:
    /home/simon/dev/utest.h/test/process.h:346:57: error: missing terminating ' character [-Werror]
      346 |                       environment,         // use parent's environment
          |                                                         ^
    /home/simon/dev/utest.h/test/process.h:347:57: error: missing terminating ' character [-Werror]
      347 |                       NULL,                // use parent's current directory
          |                                                         ^
    /home/simon/dev/utest.h/test/process.h:359:12: error: missing terminating ' character [-Werror]
      359 |   // We don't need the handle of the primary thread in the called process.
          |            ^
    /home/simon/dev/utest.h/test/process.h:430:31: error: implicit declaration of function ā€˜fdopen’; did you mean ā€˜fopen’? [-Werror=implicit-function-declaration]
      430 |     out_process->stdin_file = fdopen(stdinfd[1], "wb");
          |                               ^~~~~~
          |                               fopen
    /home/simon/dev/utest.h/test/process.h:430:29: error: assignment to ā€˜FILE *’ from ā€˜int’ makes pointer from integer without a cast [-Werror=int-conversion]
      430 |     out_process->stdin_file = fdopen(stdinfd[1], "wb");
          |                             ^
    /home/simon/dev/utest.h/test/process.h:435:30: error: assignment to ā€˜FILE *’ from ā€˜int’ makes pointer from integer without a cast [-Werror=int-conversion]
      435 |     out_process->stdout_file = fdopen(stdoutfd[0], "rb");
          |                              ^
    /home/simon/dev/utest.h/test/process.h:444:32: error: assignment to ā€˜FILE *’ from ā€˜int’ makes pointer from integer without a cast [-Werror=int-conversion]
      444 |       out_process->stderr_file = fdopen(stderrfd[0], "rb");
          |                                ^
    cc1: all warnings being treated as errors
    

    I can take care of this, but I'd like to discuss about a strategy first. Would it be ok to bump the minimal required standard to c99?

  • NAN makes test pass

    NAN makes test pass

    I have this issue where a NaN makes my test pass:

    UTEST(test, test)
    {
        float test_value = NAN;
        float epsilon = 0.001f;
        EXPECT_NEAR(1.f, test_value, epsilon); // test passes
    }
    

    Should I check for NaNs everytime I pass a number to a utest macro? Would it make sense for utest to check internally whether values passed to it are NaN before checking the condition, and failing the test if any of the values are NaN?

  • Add C++ exception support

    Add C++ exception support

    Addition of EXPECT_EXCEPTION and ASSERT_EXCEPTION. These check that a specified exception will fire when a code block is executed.

    Handling of exceptions in the test running code. Exceptions will now be caught and recorded as failures allowing further tests to continue.

    Both inspired by Acutest.

  • typeof not declared in C++ on GCC

    typeof not declared in C++ on GCC

    If I try to use utest using any of the macros that internally use typeof for a c++ program using gcc 8.3.0, I get

    utest.h:423:5: error: ā€˜typeof’ was not declared in this scope

    A fix would be to use __typeof__ instead. I can fork and create a pull request if that is a valid fix and I am not missing anything.

    I think the same is true for clang, not sure right now though.

  • Support the type printer for C11 compilers

    Support the type printer for C11 compilers

    _Generic allows us to select the value based on the type of the expression, which means we don't need to support function overloading, and means failing expressions print properly in gcc

  • Proposal to add TODO test result with yellow color tag

    Proposal to add TODO test result with yellow color tag

    Why? When writing tests it is common to put some unimportant function aside due to low-priority in order to implement tests later. It is a very dangerous practice, because you might think that the whole module is tested, but it is not always the case and some functions might be left out for later and eventually forgotten. It would be really nice if framework would allow to call UTEST_TODO() to mark test as unimplemented which would show it as yellow in the summary.

    One can argue you should use test coverage utils but lets be honest it is rarely the case.

    How? Add another result OK, FAILED, TODO with yellow color marker.

    Who? I can do it if you are willing to assist along the way to eventually PR it (so no-ones time is wasted). But if it is an easy feature I would rather let other people familiar with the library do it.

    Unrelated Notes Very nice library. The fact that tests are auto-added is a game changer. Have a great day!

  • Errors with GCC

    Errors with GCC

    One test fails:

    [ RUN      ] utest_cmdline.filter_with_list
    /home/vagrant/code/utest.h/test/main.c:87: Failure
      Expected : undef
        Actual : undef
    

    The type_printers set also outputs to the console, which is not the case on Windows with MSVC:

    [ RUN      ] type_printers.stdc
    -2147483648-9223372036854775808-9223372036854775808429496729518446744073709551615184467440737095516150.0000000.0000000.000000[       OK ] type_printers.stdc (352203ns)
    [ RUN      ] type_printers.cpp
    -2147483648-9223372036854775808-9223372036854775808429496729518446744073709551615184467440737095516150.0000000.0000000.000000[       OK ] type_printers.cpp (59254ns)
    
  • utest.h does not include time.h when compiling on ARM64 Manjaro Linux with Clang

    utest.h does not include time.h when compiling on ARM64 Manjaro Linux with Clang

    Problem: When compiling the unit tests for my project, the Clang build fails with the following errors:

    In file included from ./main.c:11:
    ././utest.h:200:19: error: variable has incomplete type 'struct timespec'
      struct timespec ts;
                      ^
    ././utest.h:200:10: note: forward declaration of 'struct timespec'
      struct timespec ts;
             ^
    ././utest.h:201:9: error: unknown type name 'clockid_t'
      const clockid_t cid = CLOCK_REALTIME;
            ^
    ././utest.h:201:25: error: use of undeclared identifier 'CLOCK_REALTIME'
      const clockid_t cid = CLOCK_REALTIME;
                            ^
    ././utest.h:203:3: warning: implicit declaration of function 'clock_gettime' is invalid in C99 [-Wimplicit-function-declaration]
      clock_gettime(cid, &ts);
      ^
    1 warning and 3 errors generated.
    

    From some experimentation, I've narrowed the source of the problem down to time.h not being included due to __GLIBC__ and __GLIBC_MINOR__ becoming undefined somewhere between including C Standard Library headers like stdio.h and utest.h being included. I unfortunately do not have the experience to know exactly why, nor could I find an immediately obvious reason as to the cause in utest.h itself.

    I have not reproduced this on other architectures using Linux, nor with other versions of Linux, but I do know that my code compiled without problem on Windows running on a 64-bit Intel processor.

    Platform: aarch64 Linux (Manjaro ARM) Compiler: clang 10.0.1

    Steps to reproduce:

    1. Pull latest utest.h
    2. Create a source file example.c with the following contents:
    #include <stdio.h>
    #include "./utest.h"
    
    UTEST_MAIN();
    
    1. Compile example.c with using the following command:
    clang -g -std=c99 ./example.c
    

    Any thoughts on why this could be happening? I plan to see if I can replicate this on Linux running on a 64-bit Intel processor to rule out the possibility of it being a problem with the POSIX headers used by Manjaro ARM.

  • error: conversion from ā€˜size_t’ compiling with -Werror=conversion

    error: conversion from ā€˜size_t’ compiling with -Werror=conversion

    Thanks for this handy unit test framework! I use it in my mpdclient project myMPD.

    Version: master Toolchain: gcc version 11.2.0 (Ubuntu 11.2.0-19ubuntu1) Target: x86_64-linux-gnu

    Full error:

    /dist/utest/utest.h: In function ā€˜utest_main’:
    /dist/utest/utest.h:1212:35: error: conversion from ā€˜size_t’ {aka ā€˜long unsigned int’} to ā€˜utest_uint32_t’ {aka ā€˜const unsigned int’} may change value [-Werror=conversion]
     1212 |       const utest_uint32_t next = ((word >> 22u) ^ word) % index;
    
  • uninitialized index member of the utest_test_state_t structure

    uninitialized index member of the utest_test_state_t structure

    image

    After line #644 the assignment to the index member is what might be mising?

        utest_state.tests[index].func = &utest_##SET##_##NAME;       \
        utest_state.tests[index].name = name;                                      \
        utest_state.tests[index].index = index;                                      \
    
  • test is not run (VS15, Release)

    test is not run (VS15, Release)

    struct utest_state is empty when run test in Release mode (Visual studio 15). I have printed: [==========] Running 0 test cases. [==========] 0 test cases ran. [ PASSED ] 0 tests. Is it ok?

    In Debug - all tests are running

  • error: double-'free' of '<unknown>' [CWE-415] [-Werror=analyzer-double-free]

    error: double-'free' of '' [CWE-415] [-Werror=analyzer-double-free]

    Error:

    third_party/utest/utest.h: In function 'utest_main':
    third_party/utest/utest.h:1122:5: error: double-'free' of '<unknown>' [CWE-415] [-Werror=analyzer-double-free]
     1122 |     free(UTEST_PTR_CAST(void *, utest_state.tests[index].name));
          |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    compilation terminated due to -Wfatal-errors.
    cc1: all warnings being treated as error
    

    Build configuration:

    āÆ ./configure
    ...
    Configuration parameters:
      AR_FLAGS                       cru
      CC                             gcc
      CC vendor                      gnu
      CC version                     10.3.0
      CFLAGS
                                     -g
                                     -O2
                                     -std=c11
                                     -fanalyzer
                                     -fdiagnostics-color=always
                                     -Wall
                                     -Wextra
                                     -Werror
                                     -Wfatal-errors
                                     -Wpedantic
                                     -pedantic-errors
                                     -Werror=missing-declarations
                                     -Werror=unused
                                     -Werror=unused-result
                                     -Werror=unused-local-typedefs
                                     -Werror=write-strings
                                     -Werror=sign-conversion
                                     -Werror=narrowing
                                     -Werror=uninitialized
                                     -Wformat=2
                                     -Wformat-security
                                     -Wformat-y2k
                                     -fstack-protector-all
      CPP                            gcc -E
      CPPFLAGS
                                     -U_FORTIFY_SOURCE
                                     -D_FORTIFY_SOURCE=2
      CXX                            g++
      CXX vendor
      CXX version
      CXXFLAGS
                                     -g
                                     -O2
      LDFLAGS
      HOST
      HOSTNAME
      OSTYPE
      uname -mrs                     FreeBSD 13.0-RELEASE amd64
      host                           amd64-unknown-freebsd13.0
      enable-hardening               yes
      enable-asan                    no
      enable-tsan                    no
      enable-ubsan                   no
    
  • work like doctest for c++?

    work like doctest for c++?

    doctest has one definition flag(DOCTEST_CONFIG_DISABLE) that can toggle testcase code(e.g. like NDEBUG) and can let me mix test code with production code easily, can utest.h do that? that is, all unit tests code are right in the production code(instead of in separate test source files), and I can turn them off for a release build.

    that make all test code just like the NDEBUG controlled assert, I can turn on and off easily, and can put testcases with the real production code together, in the same file.

    however doctest does not work for c, utest.h can, so I wonder if utest.h can do the same.

  • Color print on Visual Studio older than 2019

    Color print on Visual Studio older than 2019

    1. Hi, when running tests I have printed:

    [==========] Running 1 test cases. [ RUN ] Test0.uint8Test_default [ OK ] Test0.uint8Test_default (7700ns) [==========] 1 test cases ran. [ PASSED ] 1 tests.

    Windows 10 Pro, Vers 1909, Build: 18363.1139 MSVC 2015.

    1. it seems on line 923 there is an attempt to read an uninitialized variable. utest_state.tests[index].func(&result, utest_state.tests[index].index);
A unit testing framework for C

Check Table of Contents About Installing Linking Packaging About Check is a unit testing framework for C. It features a simple interface for defining

Jan 2, 2023
Minimal unit testing framework for C

MinUnit Minunit is a minimal unit testing framework for C/C++ self-contained in a single header file. It provides a way to define and configure test s

Dec 19, 2022
A lightweight unit testing framework for C++

Maintenance of UnitTest++, recently sporadic, is officially on hiatus until 26 November 2020. Subscribe to https://github.com/unittest-cpp/unittest-cp

Jan 1, 2023
UT: C++20 μ(micro)/Unit Testing Framework
UT: C++20 μ(micro)/Unit Testing Framework

"If you liked it then you "should have put a"_test on it", Beyonce rule [Boost::ext].UT / μt | Motivation | Quick Start | Overview | Tutorial | Exampl

Dec 29, 2022
The fastest feature-rich C++11/14/17/20 single-header testing framework
The fastest feature-rich C++11/14/17/20 single-header testing framework

master branch Windows All dev branch Windows All doctest is a new C++ testing framework but is by far the fastest both in compile times (by orders of

Jan 5, 2023
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)

Catch2 v3 is being developed! You are on the devel branch, where the next major version, v3, of Catch2 is being developed. As it is a significant rewo

Jan 8, 2023
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)

Catch2 v3 is being developed! You are on the devel branch, where the next major version, v3, of Catch2 is being developed. As it is a significant rewo

Jan 8, 2023
Simple Unit Testing for C

Unity Test Copyright (c) 2007 - 2021 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams Welcome to the Unity Test Project, one of the

Jan 5, 2023
Googletest - Google Testing and Mocking Framework

GoogleTest OSS Builds Status Announcements Release 1.10.x Release 1.10.x is now available. Coming Soon Post 1.10.x googletest will follow Abseil Live

Jan 7, 2023
A testing micro framework for creating function test doubles

Fake Function Framework (fff) A Fake Function Framework for C Hello Fake World! Capturing Arguments Return Values Resetting a Fake Call History Defaul

Dec 29, 2022
šŸ¦IceCream-Cpp is a little (single header) library to help with the print debugging on C++11 and forward.

??IceCream-Cpp is a little (single header) library to help with the print debugging on C++11 and forward.

Dec 28, 2022
Single C file, Realtime CPU/GPU Profiler with Remote Web Viewer
Single C file, Realtime CPU/GPU Profiler with Remote Web Viewer

Remotery A realtime CPU/GPU profiler hosted in a single C file with a viewer that runs in a web browser. Supported Platforms: Windows Windows UWP (Hol

Jan 8, 2023
C++ Benchmark Authoring Library/Framework

Celero C++ Benchmarking Library Copyright 2017-2019 John Farrier Apache 2.0 License Community Support A Special Thanks to the following corporations f

Jan 6, 2023
A C++ micro-benchmarking framework

Nonius What is nonius? Nonius is an open-source framework for benchmarking small snippets of C++ code. It is very heavily inspired by Criterion, a sim

Dec 19, 2022
test framework

Photesthesis This is a small, experimental parameterized-testing tool. It is intended to be used in concert with another unit-testing framework (eg. C

Jun 2, 2021
A simple framework for compile-time benchmarks

Metabench A simple framework for compile-time microbenchmarks Overview Metabench is a single, self-contained CMake module making it easy to create com

Dec 10, 2022
DotX64Dbg aims to provide a seamless way to write and test plugins for X64Dbg using .Net 5.0 and C#.
DotX64Dbg aims to provide a seamless way to write and test plugins for X64Dbg using .Net 5.0 and C#.

DotX64Dbg (EARLY ALPHA) Plugins and Scripting with C# for x64Dbg. Create Plugins for X64Dbg with ease DotX64Dbg aims to provide a seamless way to writ

Oct 16, 2022
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows and Linux.

The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows and Linux.

Jan 2, 2023
A simple C++ 03/11/etc timer class for ~microsecond-precision cross-platform benchmarking. The implementation is as limited and as simple as possible to create the lowest amount of overhead.

plf_nanotimer A simple C++ 03/11/etc timer class for ~microsecond-precision cross-platform benchmarking. The implementation is as limited and simple a

Dec 4, 2022