Giter Site home page Giter Site logo

mity / acutest Goto Github PK

View Code? Open in Web Editor NEW
316.0 17.0 93.0 206 KB

Simple header-only C/C++ unit testing facility.

License: MIT License

C++ 97.72% CMake 2.28%
c c-plus-plus unit-testing header-only mit-license cli tap-producer single-file single-header testing-tools

acutest's People

Contributors

amgross avatar andrerenaud avatar arr2036 avatar brendansimon avatar chatziko avatar cipherself avatar ctz avatar derekcresswell avatar flatcap avatar gahr avatar gdamore avatar hartwork avatar hovsater avatar mity avatar sakateka avatar terryburton avatar wheybags avatar zeehio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

acutest's Issues

For beginners: Change TEST_DUMP_MAXSIZE into a run-time limit.

Currently, there is a compile-time constant limiting length of helper messages output via TEST_DUMP macro. It would be good to change it so that people do not have to re-compile of they need to see longer message.

Because Acutest should not output too long things by default, it still should have a limit, but it should be changed into run-time one. I'd suggest that TEST_DUMP_MAXSIZE will be kept but will only determine the default length and user could specify another one by a new command line option, say --max-dump=NUMBER.

(Similar to #33.)

testsuite name

@AndreRenaud I have just noticed the xUnit XML outputs a hardcoded string ("acutest") as the testsuite name. I am wondering whether it is the right thing to do.

Consider a larger project which builds multiple test suites, all using acutest. CI or whatever harnessing is there can be confused if it understands all of them as a newer run of the same test suite, and also some summary report could be hard to decode.

Maybe using something more specific, e.g. argv[0] (or basename() of it, and on Windows without the .exe suffix) might be better?

Provide TEST_SKIP(message) macro

I do like this library quite much because it's so simple and easy to integrate.

It would be nice to be able to explicitly skip testcases when they cannot run. That is especially useful when test suites are executed in different environments and configurations and whether a testcase is executed or not can only be determined at run-time. Skipped test cases are not failures, but they are listed in the summary as skipped.

It's like this feature: https://doc.qt.io/qt-5/qttestlib-tutorial6.html

TEST_STRING_EQUAL method

Why there is no method for string comparison?
TEST_CHECK(strcmp(produced, expected) == 0) is not very comfortable.
I think for exampleTEST_STRING_EQUAL("123456789","123567899") which will write to output
smthn like "
String Check Failed
123456789
123567899
>>>4!=5
" will be very useful for many purposes
I can implement it

Multiple projects with the same cutest name

There are many unit testing facilities with the name, "Cutest", or some very similar name. Even if filtering out some mirrors/copies/forks, the current list of known Cutests so far seems like this:

Quite terrific. This shows few things:

  • That choosing the name for this project was not so good idea as it seemed when I "invented" the name.
  • That I failed to do some research to verify whether the name is not already used.
  • That we should do something with it. The open question is what as I am not sure whether renaming it would help as the damage has already been done.
  • The only positive thing is I am not alone :-)

The question is what to do now. I actually see only two reasonable approaches:

  1. Keep the current status quo. It exists for years already and, AFAIK, there was no real harm. Of course we should at least be polite and do some disambiguation in README.md or something.
  2. Rename this project to something else. With all the bad consequences because some people already know and refer to this project by its name.

I tend to stick with the first solution, at least until practice shows the current situation is unbearable.

Any opinions?

Warning `warning: variable length array folded to constant array as an extension` on Clang 10

Using this header and liking its simplicity and usability. Saved me a lot of time.

Seeing a warning when building C language tests with clang 10, with general warnings enabled.

I will probably silence this in the short term, but it looks like a fix wouldn't be too hard. I think.

clang -Iinclude -pedantic -Wall -Wextra -g -O0 -D_DEBUG_ xxx...
In file included from xxx.c:3:
include/acutest.h:1598:14: warning: variable length array folded to constant array as an extension [-Wgnu-folding-constant]
    char buf[256+OVERLAP+1];

clang --version
clang version 10.0.0-4ubuntu1 
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Getting error related to lcrt0.o library

Hi @mity , I clone the repository and tried running make command on the examples folder you have provided. I got error regarding below:

gcc -I../include  -Wall -static c-example.c -o c-example
ld: library not found for -lcrt0.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [c-example] Error 1

Any help would be appreciated, my current xcode version:

xcode-select version 2343.

I already ran xcode-select --install but still getting the same error.

Thanking You!

Allow TEST_CHECK for non-int conditions

Since acutest_check_ specifically expects an int for the condition, we cannot currently do a truthiness check with TEST_CHECK/TEST_ASSERT without a compiler warning.

For example, the following will emit a warning:

struct foo x* = ...;
TEST_CHECK(x);

Instead, we have to write it this way:

struct foo x* = ...;
TEST_CHECK(x != NULL);

I think this can be easily fixed by modifying the four macros to pass !!(cond) to acutest_check_.

Adding TEST_ASSERT (like TEST_CHECK but aborting the test on a failed condition)

TEST_CHECK currently returns a testable value. However for most of the tests that I'm writing I essentially use TEST_CHECK as an assert (ie: if it fails, there isn't much point continuing with the test). Is there any value in adding a TEST_ASSERT macro which behaves this way? Basically:
#define TEST_ASSERT(a) do { if (!TEST_CHECK(a)) return; } while (0)

TEST_CASE should evaluate as a statement (no trailing semicolon)

Clang-Tidy found this.

TEST_CASE(name) ends with a semicolon, which means that if you use it like this:

TEST_CASE(x == 1);

The compiler complains about an empty statement (caused by the redundant semicolon). This can also lead to surprises if this is used in contexts without enclosing braces, so it's not recommended.

Simple solution is just to elide the trailing semicolon.

PR with this is on the way.

flush stdout and stderr before aborting

When using TEST_ASSERT and TEST_ASSERT_, it seems the program exits before stdout and stderr are flushed, meaning the corresponding messages don't show up in the output.

Please add the following to acutest_abort_ before actually aborting.

fflush(stdout);
fflush(stderr);

acutest/include/acutest.h

Lines 870 to 880 in 1849c02

void
acutest_abort_(void)
{
if(acutest_abort_has_jmp_buf_) {
longjmp(acutest_abort_jmp_buf_, 1);
} else {
if(acutest_current_test_ != NULL)
acutest_fini_(acutest_current_test_->name);
abort();
}
}

Testing C code that abort()s

Thanks a lot for this super neat test library!

One useful feature I feel is missing is the ability to test a function that is meant to abort(), typically due to some failing assert(...) in the code. It can be viewed as the poor cousin of TEST_EXCEPTION for C. It's useful for testing that problematic conditions are properly detected and aborted. Moreover, such tests are useful for reaching 100% branch coverage, otherwise one branch of the assert is never hit.

This should be easily implementable by trapping SIGABRT and longjmping back in the test. It can be named TEST_ABORT, TEST_SIGNAL (maybe for testing any signal) or something like that.

Your thoughts? If you're interested I can give it a shot.

Is this repo abandoned?

I raised issue #62 and PR #63 two months ago, but so far they have been ignored. Is this repo abandoned?

I don't mean to be rude, just want to know if I should directly update the vendored copy instead of fixing the upstream.

Implement debugger detection on Mac OS X (and other platforms)

On systems where supported (all Posix systems and Windows), Acutest by default executes each test in a child process to isolate them from each other. However, in order to improve debugability, this default behavior is suppressed when we detect the main process is executed under a debugger or being traced because, in general, debugging forking processes is much more pain.

This detection is currently implemented only for Windows and Linux. It would be great to have this also for other Posix platforms (if they offer an appropriate API for that). Especially on Mac OS X, given its popularity.

Sign conversion warnings when compiling with -Wsign-conversion under clang

I have copied latest master into my project, but I have very strict compiler flags. Here is the output:

/Users/jerry/go/src/github.com/xor-gate/eresp/tests/acutest.h:206:16: warning: implicit conversion changes signedness: 'int' to 'size_t'
      (aka 'unsigned long') [-Wsign-conversion]
        return printf("%s", buffer);
        ~~~~~~ ^~~~~~~~~~~~~~~~~~~~
/Users/jerry/go/src/github.com/xor-gate/eresp/tests/acutest.h:221:13: warning: implicit conversion changes signedness: 'int' to 'size_t'
      (aka 'unsigned long') [-Wsign-conversion]
        n = printf("%s", buffer);
          ~ ^~~~~~~~~~~~~~~~~~~~
/Users/jerry/go/src/github.com/xor-gate/eresp/tests/acutest.h:300:18: warning: implicit conversion changes signedness: 'int' to 'unsigned long'
      [-Wsign-conversion]
            n += printf("%s:%d: Check ", file, line);
              ~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/jerry/go/src/github.com/xor-gate/eresp/tests/acutest.h:304:14: warning: implicit conversion changes signedness: 'int' to 'unsigned long'
      [-Wsign-conversion]
        n += vprintf(fmt, args);
          ~~ ^~~~~~~~~~~~~~~~~~
/Users/jerry/go/src/github.com/xor-gate/eresp/tests/acutest.h:732:77: warning: implicit conversion changes signedness: 'int' to 'unsigned long'
      [-Wsign-conversion]
    tests__ = (const struct test__**) malloc(sizeof(const struct test__*) * test_list_size__);
                                                                          ~ ^~~~~~~~~~~~~~~~
/Users/jerry/go/src/github.com/xor-gate/eresp/tests/acutest.h:733:50: warning: implicit conversion changes signedness: 'int' to 'unsigned long'
      [-Wsign-conversion]
    test_flags__ = (char*) malloc(sizeof(char) * test_list_size__);
                                               ~ ^~~~~~~~~~~~~~~~
/Users/jerry/go/src/github.com/xor-gate/eresp/tests/acutest.h:738:52: warning: implicit conversion changes signedness: 'int' to 'unsigned long'
      [-Wsign-conversion]
    memset((void*) test_flags__, 0, sizeof(char) * test_list_size__);
                                                 ~ ^~~~~~~~~~~~~~~~
/usr/include/secure/_string.h:77:38: note: expanded from macro 'memset'
  __builtin___memset_chk (dest, val, len, __darwin_obsz0 (dest))
                                     ^~~
/Users/jerry/go/src/github.com/xor-gate/eresp/tests/reader.c:34:9: warning: missing field 'func' initializer [-Wmissing-field-initializers]
    { 0 }
        ^

For the last test list entry create a macro to have all fields initialized instead of incorrect {0}:

#define TEST_LIST_END {NULL, NULL}

Paths in the verbose mode.

TL;DR: With the --verbose option, I am not happy with the too long paths to the source files in Acutest output.

Normally, Acutest outputs only basename(__FILE__). In verbose mode it currently outputs complete __FILE__.

However it does not have a consistent behavior because it is highly build system dependent. E.g. when using cmake -G "Unix Makefiles" it leads to absolute paths, with cmake -G "Ninja" there are relative paths from the build dir. I guess various unnamed IDEs also may have some funny ideas how exactly they launch the compiler.

In either case it often makes the --verbose output much harder to parse for human eyes.

For illustration...
Test empty:
  /home/mity/prj/c-reusables/tests/test-rbtree.c:110: Check rbtree_verify(&tree) == 0... ok
  /home/mity/prj/c-reusables/tests/test-rbtree.c:111: Check rbtree_is_empty(&tree)... ok
  /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
  /home/mity/prj/c-reusables/tests/test-rbtree.c:112: Check rbtree_insert(&tree, make_val(42), val_cmp) == 0... ok
  /home/mity/prj/c-reusables/tests/test-rbtree.c:113: Check rbtree_verify(&tree) == 0... ok
  /home/mity/prj/c-reusables/tests/test-rbtree.c:114: Check !rbtree_is_empty(&tree)... ok
  /home/mity/prj/c-reusables/tests/test-rbtree.c:116: Check rbtree_is_empty(&tree)... ok
  SUCCESS: All conditions have passed.

Test insert:
  Case Ascending order:
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:154: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:156: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:158: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
  Case Descending order:
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:154: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:156: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:158: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
  Case Randomized order:
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:70: Check v != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:142: Check rbtree_insert(&tree, make_val(values[i]), val_cmp) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:143: Check rbtree_verify(&tree) == 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:149: Check rbtree_lookup(&tree, &key.the_node, val_cmp) != NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:154: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:156: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:158: Check rbtree_lookup(&tree, &key.the_node, val_cmp) == NULL... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
    /home/mity/prj/c-reusables/tests/test-rbtree.c:163: Check rbtree_insert(&tree, &tmp.the_node, val_cmp) != 0... ok
  SUCCESS: All conditions have passed.

Summary:
  Count of all unit tests:        2
  Count of run unit tests:        2
  Count of failed unit tests:     0
  Count of skipped unit tests:    0
SUCCESS: All unit tests have passed.

Therefore, I am currently thinking about making to just output basename(__FILE__) even in the verbose output. It may be small change in the code but possibly with bigger impact on usability. So the question of the day is:

Does anyone find the current behavior useful?
Or perhaps someone has a viable counter-proposal?

Memory leak in children

After fork(), test_details_ is never free’d, as is is in the parent process.

I use Valgrind with my students projects to detect memory leaks, and the "still unreachable" message, though harmless, confuses them. (The warning does not appear when running with -E, of course.)

If nobody beats me to it, in a few days I can send a PR to fix this.

Windows outputs "Debug Error - Abort() was called" on every failed test

When compiling with MSVC, Windows outputs this on every failing test:

image

This can easily be disabled by calling the following (See MSDN):

_set_abort_behavior(0, _WRITE_ABORT_MSG);

I'm just not sure where, otherwise this would be a PR!

An other solution would be to simply not use abort() on windows, but a special exit-code.

Q: constructor/destructor functions?

Would you consider adding user-defined functions that'd be called at the beginning/end of main()
Several of our tests need to have setlocale() called beforehand, so it'd be nice to centralise that.

Something simple like:

#define ACUTEST_CTOR my_constructor

main()
{
#ifdef ACUTEST_CTOR
  ACUTEST_CTOR();
#endif
}

If yes, I'll create a PR

Call cleanup handler after assert fail

When a testcase fails, I want to abort it immediately (TEST_ASSERT), but I also want to clean up resources. Here is my current workaround:

if (!TEST_CHECK(condition)) {
   do_cleanup();
   return;
}

I was expecting that the cleanup handler is executed regardless of the test result, but that is apparently not the case. A solution that allows parameterized cleanup would be nice to have.

Make the output adapt to terminal size

Make the output, especially as generated by the macros TEST_CHECK(), TEST_MSG() and TEST_DUMP(), automatically adapt to the current terminal size, so that it looks good in a reasonably small terminal window but can use effectively more space if the terminal window is big.

This should involve:

  1. Explore what API is available for the purpose on the platform of your choice.
  2. A pre-processor magic to enable the new platform-specific code only on the given platform.
  3. Breaking the long outputs into multiple lines, depending on the width of the terminal.
  4. And still respect the current indentation level, as set via test_line_indent__().

ACUTest does not build with Embaradero C++ Builder

To get ACUTest to build with Embarcadero C++ Builder I had to change add test_colorize = isatty(_fileno(stdout)); as follows.

#if defined ACUTEST_UNIX__
    test_colorize__ = isatty(STDOUT_FILENO);
#elif defined ACUTEST_WIN__
 #if defined __BORLANDC__
    test_colorize__ = isatty(_fileno(stdout));
 #else
    test_colorize__ = _isatty(_fileno(stdout));
 #endif
#else
    test_colorize__ = 0;
#endif

Timing calculations are wrong

There are a few issues with the timing calculations:

  • A rounding / type conversion error can lead to wildly incorrect values (I had one report that came up at 7 seconds, but really took something on the order of a few dozen milliseconds). This was seen on Windows. Preserving the values as nanoseconds and only doing a division at the end gives better results. (And it appears that dividing by 1e9 is better than multiplying by 1e-9 if you want to avoid loss due to casting bugs.)

  • The Linux MONONTONIC_RAW clock should not really be used. Besides not being portable, the values are not guaranteed to be microseconds -- and really you do want any adjtime adjustments because those reflect real-world timekeeping. (This makes it not as good for reproducible benchmarking, but the cpu clock is better for that anyway.)

  • There is an order of magnitude bug in the POSIX timings, leading to times being reported as 1/10th their actual value (this lead to a lot of confusion for me at one point). Hint, 1 billionth is not 10e-9, but rather 1e-9.

I have a PR coming that addresses these.

Multiple definition of `test_check__'

Hi, I'm trying to use this nice library, but I have an issue. It seems that the macros are defined in multiple files, but I don't know exactly, because I'm a C beginner. I'm using this library following this workflow:

  • A main.c file that contains TEST_LIST with all tests;
  • A tests_list.h file that contains all definition of tests;
  • A test_example.c file that contains the implementation of a test.

To reproduce the error:
main.c

#include "acutest.h"

#include "tests_list.h"

TEST_LIST = {
        { "example", test_example },
        { 0 }
};

tests_list.h

#ifndef TESTS_LIST_H
#define TESTS_LIST_H

void test_example(void);

#endif /* TESTS_LIST_H */

test_example.c

#include "acutest.h"

#include <stdlib.h>

void test_example(void)
{
        void* mem;
        int a, b;

        mem = malloc(10);
        TEST_CHECK(mem != NULL);

        mem = realloc(mem, 20);
        TEST_CHECK(mem != NULL);

        a = 1;
        b = 2;
        TEST_CHECK_(a + b == 3, "Expected %d, got %d", 3, a + b);
}

Compile with:
gcc -c test_example.c
gcc -c main.c
gcc -o example main.o test_example.o

The output of the last command is:

test_example.o: In function `test_check__':
test_example.c:(.text+0x1ba): multiple definition of `test_check__'
main.o:main.c:(.text+0x1ba): first defined here
test_example.o: In function `main':
test_example.c:(.text+0x7e4): multiple definition of `main'
main.o:main.c:(.text+0x7e4): first defined here
collect2: error: ld returned 1 exit status

I asked to stb repository (because stb project is like this), but I don't understand where is the problem...

program crash as a way to pass the test

In the examples folder you have this piece of code which shows a test crashing:

void
test_crash(void)
{
    int* invalid = ((int*)NULL) + 0xdeadbeef;

    *invalid = 42;
    TEST_CHECK_(1 == 1, "We should never get here, due to the write into "
                        "the invalid address.");
}

However, it makes the test fail. I didn't find a way to make it pass while crashing.
Is this feature available? If not, do you like the idea? I could try to write a patch for it if so. :)

Can exception handling be disabled for use in testing embedded C++ systems?

Hello, we are trying to do some testing of a resource-constrained C/C++ embedded project, which has exception handling disabled. However, it seems like acutest is set up to handle testing of exceptions. Is there a way to configure acutest so that no exception handling or testing is supported for use with embedded systems? Thank you!

Any way to test for a non-zero exit(status) condition?

First off, great test facility!

However, when testing error handling code to get full coverage sometimes exit is called with a non-zero status.
It would be nice if one could expect a specific exit status, similar to how one can expect a specific C++ exception to be thrown.

This is on Unix (Linux and FreeBSD) and forking is being done.

Is this something that you would accept a PR for? I'd only be able make it for Unix as I don't have access to any Windows development environment for stuff like this.

I'd also like to test for expected signals, in addition to expected non-zero status return.

For my own testing I'm applying this patch (which does not address those issues), and I'm not expecting to make PR for it:

int acutest_check_(int cond, const char* file, int line, const char* fmt, ...);
 void acutest_case_(const char* fmt, ...);
@@ -1132,7 +1132,8 @@ acutest_run_(const struct acutest_test_* test, int index, int master_index)
             } else if(WIFSIGNALED(exit_code)) {
                 char tmp[32];
                 const char* signame;
-                switch(WTERMSIG(exit_code)) {
+                const int signum = WTERMSIG(exit_code);
+                switch(signum) {
                     case SIGINT:  signame = "SIGINT"; break;
                     case SIGHUP:  signame = "SIGHUP"; break;
                     case SIGQUIT: signame = "SIGQUIT"; break;
@@ -1141,9 +1142,10 @@ acutest_run_(const struct acutest_test_* test, int index, int master_index)
                     case SIGSEGV: signame = "SIGSEGV"; break;
                     case SIGILL:  signame = "SIGILL"; break;
                     case SIGTERM: signame = "SIGTERM"; break;
+                    case SIGFPE:  signame = "SIGFPE"; break;
                     default:      sprintf(tmp, "signal %d", WTERMSIG(exit_code)); signame = tmp; break;
                 }
-                acutest_error_("Test interrupted by %s.", signame);
+                acutest_error_("Test interrupted by %s (%d).", signame, signum);
             } else {
                 acutest_error_("Test ended in an unexpected way [%d].", exit_code);
             }

Compile works but program does not finish and takes 100% CPU ?!

Hi, I just started with acutest (compiles 30 times faster than Catch2 :o ).

But when I run the compiled program,

  • there is no output,
  • it does not finish,
  • it takes 100% CPU.

Minimal example:

#include "acutest.h"

void test_mean() {
  TEST_CHECK( 5 == 5 );
}

TEST_LIST = {
   { "mean", test_mean }
};
g++ -o test test.cpp
./test

Compiles without error but execution never finishes...

Any ideas?

“Test Anything Protocol” output mode

TAP (Test Anything Protocol) is a simple text protocol to deal with test results. It should be quite easy to implement, and would make acutest easily integrate with existing tools.

A TAP output looks like this:

1..4
ok 1 - Input file opened
not ok 2 - First line of the input valid
ok 3 - Read the rest of the file
not ok 4 - Summarized correctly # TODO Not written yet

It would enable for example to produce JUnit XML files for the test results and displaying them in GitLab merge requests, or to display the test results in Jenkins easily

For beginners: Change TEST_MSG_MAXSIZE into a run-time limit.

Currently, there is a compile-time constant limiting length of helper messages output via TEST_MSG macro. It would be good to change it so that people do not have to re-compile of they need to see longer message.

Because Acutest should not output too long things by default, it still should have a limit, but it should be changed into run-time one. I'd suggest that TEST_MSG_MAXSIZE will be kept but will only determine the default length and user could specify another one by a new command line option, say --max-msg=NUMBER.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.