Skip to content

A C unit testing library in 1 file. No dependencies, no dynamic allocation. ISC licensed.

Notifications You must be signed in to change notification settings

ultravideo/greatest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

greatest

A unit testing system for C, contained in 1 file. It doesn't use dynamic allocation or depend on anything beyond ANSI C89, and the test scaffolding should build without warnings under -Wall -pedantic.

To use, just #include greatest.h in your project.

There are some compile time options, and slightly nicer syntax for parametric testing (running tests with arguments) is available if compiled with -std=c99.

Also, I wrote a blog post with more information.

theft, a related project, adds property-based testing.

Available Assertions

ASSERT(COND) and ASSERTm(MSG, COND)

Assert that COND evaluates to a true value.

ASSERT_FALSE(COND) and ASSERT_FALSEm(MSG, COND)

Assert that COND evaluates to a false value.

ASSERT_EQ(EXPECTED, ACTUAL) and ASSERT_EQm(MSG, EXPECTED, ACTUAL)

Assert that EXPECTED == ACTUAL. To compare with a custom equality test function, use ASSERT_EQUAL_T instead. To print the values if they differ, use ASSERT_EQ_FMT.

ASSERT_EQ_FMT(EXPECTED, ACTUAL, FORMAT) and ASSERT_EQ_FMTm(MSG, EXPECTED, ACTUAL, FORMAT)

Assert that EXPECTED == ACTUAL. If they are not equal, print their values using FORMAT as the printf format string.

For example: ASSERT_EQ_FMT(123, result, "%d");

ASSERT_IN_RANGE(EXPECTED, ACTUAL, TOLERANCE) and ASSERT_IN_RANGEm(MSG, EXPECTED, ACTUAL, TOLERANCE)

Assert that ACTUAL is within EXPECTED +/- TOLERANCE, once the values have been converted to a configurable floating point type (GREATEST_FLOAT).

ASSERT_STR_EQ(EXPECTED, ACTUAL) and ASSERT_STR_EQm(MSG, EXPECTED, ACTUAL)

Assert that strcmp(EXPECTED, ACTUAL) == 0.

ASSERT_EQUAL_T(EXPECTED, ACTUAL, TYPE_INFO, UDATA) and ASSERT_EQUAL_Tm(MSG, EXPECTED, ACTUAL, TYPE_INFO, UDATA)

Assert that EXPECTED and ACTUAL are equal, using the greatest_equal_cb function pointed to by TYPE_INFO->equal to compare them. The function's UDATA argument can be used to pass in arbitrary user data (or NULL). If the values are not equal and the TYPE_INFO->print function is defined, it will be used to print an "Expected: X, Got: Y" message.

ASSERT_OR_LONGJMP(COND) and ASSERT_OR_LONGJMPm(MSG, COND)

Assert that COND evaluates to a true value. If not, then use longjmp(3) to immediately return from the test case and any intermediate function calls. (If built with GREATEST_USE_LONGJMP set to 0, then all setjmp/longjmp-related functionality will be compiled out.)

In all cases, the m version allows you to pass in a customized failure message. If an assertion without a custom message fails, greatest uses C preprocessor stringification to simply print the assertion's parameters.

Basic Usage

#include "greatest.h"

TEST x_should_equal_1() {
    int x = 1;
    ASSERT_EQ(1, x);                              /* default message */
    ASSERT_EQm("yikes, x doesn't equal 1", 1, x); /* custom message */
    /* printf expected and actual values as "%d" if they differ */
    ASSERT_EQ_FMT(1, x, "%d");
    PASS();
}

SUITE(the_suite) {
    RUN_TEST(x_should_equal_1);
}

/* Add definitions that need to be in the test runner's main file. */
GREATEST_MAIN_DEFS();

int main(int argc, char **argv) {
    GREATEST_MAIN_BEGIN();      /* command-line arguments, initialization. */
    RUN_SUITE(the_suite);
    GREATEST_MAIN_END();        /* display results */
}

Output:

$ make simple && ./simple
cc -g -Wall -Werror -pedantic    simple.c   -o simple

* Suite the_suite:
.
1 tests - 1 pass, 0 fail, 0 skipped (5 ticks, 0.000 sec)

Total: 1 tests (47 ticks, 0.000 sec), 3 assertions
Pass: 1, fail: 0, skip: 0.

Test cases should call assertions and then end in PASS(), SKIP(), FAIL(), or one of their message variants (e.g. SKIPm("TODO");). If there are any test failures, the test runner will return 1, otherwise it will return 0. (Skips do not cause a test runner to report failure.)

Tests and suites are just functions, so normal C scoping rules apply.

(For more examples, look at example.c and example-suite.c.)

Sub-Functions

Because of how PASS(), ASSERT(), FAIL(), etc. are implemented (returning a test result enum value), calls to functions that use them directly from test functions must be wrapped in CHECK_CALL:

TEST example_using_subfunctions(void) {
    CHECK_CALL(less_than_three(5));
    PASS();
}

This is only necessary if the called function can cause test failures.

Command Line Options

Test runners build with the following command line options:

Usage: (test_runner) [-hlfv] [-s SUITE] [-t TEST]
  -h        print this Help
  -l        List suites and their tests, then exit
  -f        Stop runner after first failure
  -v        Verbose output
  -s SUITE  only run suite w/ name containing SUITE substring
  -t TEST   only run test w/ name containing TEST substring

If you want to run multiple test suites in parallel, look at parade.

Aliases

All the Macros exist with the unprefixed notation and with the prefixed notation, for example:

SUITE is the same as GREATEST_SUITE

Checkout the source for the entire list.

These aliases can be disabled by #define-ing GREATEST_USE_ABBREVS to 0.

Color Output

If you want color output (PASS in green, FAIL in red, etc.), you can pipe the output through the included greenest script:

$ ./example -v | greenest

greatest itself doesn't have built-in coloring to stay small and portable.

About

A C unit testing library in 1 file. No dependencies, no dynamic allocation. ISC licensed.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C 98.4%
  • Makefile 1.1%
  • Awk 0.5%