greatest

repository·release·Indexed 23 days ago

https://github.com/silentbicycle/greatest

A small, portable, and lightweight C testing library contained in a single header file. It depends only on ANSI C89, uses no dynamic allocation, and is suitable for both embedded systems and general-purpose C/C++ applications. Version v1.5.0 provides a test runner with CLI filtering, randomized test shuffling, and a programmatic API for library integration.

Tokens
2.5K
Snippets
7
Records
14
Agent score
32%

What's inside greatest

  1. Use assertions in greatest

    release
    Assertions are used to validate conditions. If an assertion fails, the current test is marked as failed. Most assertions have a custom message variant with an m suffix (e.g., ASSERT_EQm("msg", expected, actual)) which accepts a message string as the first argument.
  2. How to signal test results with PASS, FAIL, and SKIP

    release

    Every test case must end by calling one of the following macros to update internal bookkeeping and return from the test function:

    • PASS() / PASSm("msg"): Marks the test as successful. Prints a dot (verbosity 0) or the test name and message (verbosity >= 1).
    • FAIL() / FAILm("msg"): Marks the test as failed. Always prints FAIL test_name: msg file:line.
    • SKIP() / SKIPm("msg"): Marks the test as skipped. Skips do not cause the test runner to report failure. Useful for TODOs or environment-specific tests. Prints an 's' (verbosity 0) or the test name and message (verbosity >= 1).
  3. Use greatest as a library instead of a CLI runner

    release

    Instead of using GREATEST_MAIN_BEGIN(), you can integrate greatest into your own program as a library.

    1. Use GREATEST_INIT() to initialize or re-initialize the framework.
    2. Use GREATEST_PRINT_REPORT() to print the report to GREATEST_STDOUT.
    3. Alternatively, use greatest_get_report(&report) to retrieve the pass, fail, skip, and assertion counters.

    Equivalent programmatic functions for CLI flags:

    • greatest_stop_at_first_fail()
    • greatest_abort_on_fail()
    • greatest_list_only()
    • greatest_set_exact_name_match()
    • greatest_set_suite_filter(const char *filter)
    • greatest_set_test_filter(const char *filter)
    • greatest_set_test_exclude(const char *filter)
    • greatest_get_verbosity()
    • greatest_set_verbosity(unsigned int verbosity)
  4. Basic usage of greatest

    release

    A test is defined as a function that executes assertions and concludes with a status macro like PASS(), FAIL(), or SKIP(). Tests can be run individually using RUN_TEST(test_name) or grouped into suites using SUITE(suite_name) and executed with RUN_SUITE(suite_name).

    To create a test runner, use the following boilerplate in your main function:

    1. GREATEST_MAIN_DEFS(): Provides definitions for the runner.
    2. GREATEST_MAIN_BEGIN(): Initializes command-line options and the runner.
    3. RUN_SUITE(...) or RUN_TEST(...): Executes your tests.
    4. GREATEST_MAIN_END(): Displays the final results.
    #include "greatest.h"
    
    /* A test runs various assertions, then calls PASS(), FAIL(), or SKIP(). */
    TEST x_should_equal_1(void) {
        int x = 1;
        ASSERT_EQ(1, x);
        PASS();
    }
    
    /* Suites can group multiple tests with common setup. */
    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();
    
        /* Tests can also be gathered into test suites. */
        RUN_SUITE(the_suite);
    
        GREATEST_MAIN_END();        /* display results */
    }
  5. Set up greatest for C testing

    release

    To use greatest, simply include the single header file greatest.h in your project. It is a lightweight, portable testing system that depends only on ANSI C89 and does not use dynamic allocation. Most features are optional, making it easy to integrate into existing C or C++ codebases.

    #include "greatest.h"
  6. Enable color output and TAP format

    release

    Since greatest does not include built-in coloring to remain portable, you can use provided scripts to format the output:

    Color Output: Pipe output through the greenest script (requires a Unix-like environment):

    $ ./example -v | greenest

    TAP Format: Convert verbose output to TAP version 13 format using the entapment awk script:

    ./example -v | contrib/entapment
  7. Run tests with random shuffling

    release

    To prevent accidental coupling between tests, you can run suites or tests in a randomized order using SHUFFLE_SUITES or SHUFFLE_TESTS. These macros require a seed to ensure reproducibility.

    Warning: Avoid running tests directly inside a SHUFFLE_SUITES block without a RUN_SUITE call, as the macro expands to a loop that will execute the code on every iteration.

    /* Shuffling suites */
    SHUFFLE_SUITES(seed, {
        RUN_SUITE(suite1);
        RUN_SUITE(suite2);
        RUN_SUITE(suite3);
        RUN_SUITE(suite4);
        RUN_SUITE(suite5);
    });
    
    /* Shuffling tests */
    SHUFFLE_TESTS(seed, {
        RUN_TEST(test_a);
        RUN_TEST1(test_b, 12345);
        RUN_TEST(test_c);
        RUN_TESTp(test_d, "some_argument");
        RUN_TEST(test_e);
    });
  8. Set a test name suffix with greatest_set_test_suffix

    release

    Use greatest_set_test_suffix(suffix) to append a custom string to the name of the next test being run. This is useful for parameterized tests where you want to distinguish between multiple runs of the same test function in the output (e.g., test_name_suffix).

    Key details:

    • The suffix is included in pass/fail/skip messages and name-based filtering.
    • The suffix is copied into an internal buffer. You can increase this buffer size by #define-ing GREATEST_TESTNAME_BUF_SIZE (defaults to 128 bytes).
    • The suffix pointer is cleared after each RUN_TEST* call, making it safe to use stack-allocated buffers for the suffix.
    for (i = 0; i < row_count; i++) {
        const struct table_row *row = &table[row_count];
        greatest_set_test_suffix(row->name);
        RUN_TEST1(test_with_arg, row);
    }
  9. Wrap sub-functions in CHECK_CALL

    release

    If a function called within a test returns an enum greatest_test_res and can cause test failures (using macros like PASS(), ASSERT(), or FAIL()), you must wrap the call in CHECK_CALL to correctly handle the returned test result enum.

    TEST example_using_subfunctions(void) {
        CHECK_CALL(less_than_three(5));
        PASS();
    }
  10. Reference: Standard Assertions

    release

    A collection of standard assertions for validating conditions, equality, and comparisons.

    ### `ASSERT(COND)`
    Assert that `COND` evaluates to a true (non-zero) value.
    
    ### `ASSERT_FALSE(COND)`
    Assert that `COND` evaluates to a false (zero) value.
    
    ### `ASSERT_EQ(EXPECTED, ACTUAL)`
    Assert that `EXPECTED == ACTUAL`.
    
    ### `ASSERT_NEQ(EXPECTED, ACTUAL)`
    Assert that `EXPECTED != ACTUAL`.
    
    ### `ASSERT_GT(EXPECTED, ACTUAL)`
    Assert that `EXPECTED > ACTUAL`.
    
    ### `ASSERT_GTE(EXPECTED, ACTUAL)`
    Assert that `EXPECTED >= ACTUAL`.
    
    ### `ASSERT_LT(EXPECTED, ACTUAL)`
    Assert that `EXPECTED < ACTUAL`.
    
    ### `ASSERT_LTE(EXPECTED, ACTUAL)`
    Assert that `EXPECTED <= ACTUAL`.