mity / acutest Goto Github PK
View Code? Open in Web Editor NEWSimple header-only C/C++ unit testing facility.
License: MIT License
Simple header-only C/C++ unit testing facility.
License: MIT License
You can use dist: flag to change to focal that ships with gcc 9.3.0 which will support c std 17
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.)
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.
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!
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
Hi, I just started with acutest (compiles 30 times faster than Catch2 :o ).
But when I run the compiled program,
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?
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.
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?
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 abort
ed. 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 longjmp
ing 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.
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:
The question is what to do now. I actually see only two reasonable approaches:
README.md
or something.I tend to stick with the first solution, at least until practice shows the current situation is unbearable.
Any opinions?
This is probably a stretch, but is there a way to get code coverage reports? (percentage of lines covered, lines not covered, etc.)
When compiling with MSVC, Windows outputs this on every failing test:
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.
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}
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
.
Would you like to replace more defines for constant values by enumerations to stress their relationships?
Don't know if you're interested, but I wrote a tutorial on CUTest at (https://github.com/tomcam/mity-cutest/blob/master/README.md). Happy to make any changes/additions to it, submit as PR, whatever.
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!
@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?
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. :)
Hi @mity ,
If you stopped to maintain this repo, please give someone write access to it so it could continue be approved, it is really great repo.
I would like to point out that an identifier like “test_list__
” does eventually not fit to the expected naming convention of the C++ language standard.
Would you like to adjust your selection for unique names?
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
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)
In main()
, on line 1838, there is this call:
acutest_cmdline_read_(acutest_cmdline_options_, argc, argc, acutest_cmdline_callback_)
which on line 1438, calls the callback
argument like this:
ret = callback(opt->id, NULL);
where callback
is acutest_cmdline_callback_)
. This callback then on line 1681 calls:
if (acutest_select_(arg) == 0)
where arg
was NULL
. This then (on line 1059) calls:
if (strcmp(acutest_list_[i].name, pattern) == 0)
Yet pattern
, the parameter holding the value of arg
, is a null pointer.
According to ISO C11, 7.1.4, "Use of library functions":
Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If an argument to a function has an invalid value (such as [...] a null pointer [...]) [...], the behavior is undefined.
The description of strcmp()
in 7.24.4 does not state otherwise, so the behavior is undefined, and the above call to strcmp()
invokes undefined behavior.
This was found when compiling the code with -fanalyzer
with GCC 13.1.
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:
test_line_indent__()
.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.
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
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.
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
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_
.
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);
}
https://github.com/onqtam/doctest/blob/master/doc/markdown/configuration.md#doctest_config_disable
with this I can put some test case code right in the production code, this flag works just like NDEBUG for assertions which is very convenient sometimes. unfortunately doctest does not support C code.
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
Would you like to add more error handling for return values from calls of a function like printf()?
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);
Lines 870 to 880 in 1849c02
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.
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.
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:
main.c
file that contains TEST_LIST
with all tests;tests_list.h
file that contains all definition of tests;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...
How do I list tests in multiple test files and have them aggregated so I can test everything in one executable?
Could you add this to the tutorial or other documentation please.
Thanks :)
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
Add utility of -jXX to run the unit tests (that anyway running in separate process) in parallel.
To avoid prints that will mix together, need that the processes won't write to stdout but will write to other place and just upon termination it will be copied to stdout. In case of no parallel, the output should go to stdout.
This change should be as light in runtime as can so it will really gain better time even for short tests.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.