Skip to content
Customization

Customization

Implementation and main

JC_TEST_IMPLEMENTATION

Define JC_TEST_IMPLEMENTATION before including the appropriate header in exactly one translation unit. Other translation units include the header without the definition. The C and C++ headers use separate runtimes and must not both provide their implementations in one executable.

JC_TEST_USE_DEFAULT_MAIN

Define JC_TEST_USE_DEFAULT_MAIN to provide main(), initialize jc_test, and run every registered test. This also enables JC_TEST_IMPLEMENTATION, so do not provide another implementation in the same executable.

Output

JC_TEST_OUTPUT_FN

Overrides the byte-oriented output function in both runtimes. Define it to the name of a function with this signature before including the implementation:

void custom_output(const char* text, size_t length);

The buffer is not required to be null-terminated; always honor length.

JC_TEST_LOGGER_CLASS

C++ only. Replaces the default jc_test_print_logger class. The replacement must provide the same constructor, destructor, fixture/test callbacks, summary callback, failure callback, and Log/Logf interface. Prefer JC_TEST_OUTPUT_FN when only the output destination changes.

JC_TEST_FLUSH_OUTPUT

C only. Overrides the function-like macro called after immediate failures and the final summary. Custom buffered output functions can use it to flush their destination.

JC_TEST_USE_PRINTF

Uses printf instead of fwrite in the default output implementation. It has no effect when JC_TEST_OUTPUT_FN is supplied.

Runtime configuration

Define these macros before including the implementation header.

MacroAvailabilityPurpose
JC_TEST_USE_COLORSC and C++Set to 1 or 0 to force ANSI colors on or off instead of detecting a terminal.
JC_TEST_NO_DEATH_TESTC and C++Disable death-test signal handling. Death assertions then compile as no-ops.
JC_TEST_TIMING_FUNCC and C++Replace the microsecond timing function used around tests.
JC_TEST_DBG_BREAK()C and C++Replace the debugger trap used by --test-break-on-fail.
JCT_IS_DEBUGGER_ATTACHED()C and C++Return nonzero when break-on-failure should be enabled automatically.
JC_TEST_FAILURE_MALLOCC and C++Allocate failure-recap records and messages.
JC_TEST_FAILURE_REALLOCC and C++Grow formatted failure messages.
JC_TEST_FAILURE_FREEC and C++Release failure-recap allocations.
JC_TEST_ASSERT_FNC++ onlyReplace internal invariant assertions.
JC_TEST_EXITC and C++Replace process termination used for invalid runtime arguments.
JC_TEST_SNPRINTFC++ onlyReplace the platform snprintf spelling.
JC_TEST_ISATTYC++ onlyReplace terminal detection used by automatic color selection.

The three failure-allocation hooks must be supplied as a compatible set. If retaining detailed failure records runs out of memory, tests continue and the summary reports how many details were dropped.

When replacing JC_TEST_TIMING_FUNC in C++, define jc_test_time_t before including the header as well. The function must return monotonically increasing microseconds in that type. C always uses the provided uint64_t jc_test_time_t.

Custom type formatting

Custom value formatters are a C++ feature of jc_test.hpp. The C11 generic assertions intentionally accept the documented scalar set and reject aggregate values at compile time.

It’s beneficial to be able to convert your custom types to a human readable string. If your type doesn’t match any of the supported types, it will default to the "?" output, which isn’t very helpful.

All that is needed it to make a function available for the template matching to find it.

Here is an example that takes a custom enum and converts that to a readable output:

#include <stdint.h>

#define JC_TEST_IMPLEMENTATION
#include <jc_test.hpp>

enum Result { RESULT_OK, RESULT_FAIL };

static const char* ResultToString(Result r) {
    switch(r) {
        case RESULT_OK: return "RESULT_OK";
        case RESULT_FAIL: return "RESULT_FAIL";
    }
}

template <> char* jc_test_print_value(char* buffer, size_t buffer_len, Result r) {
    return buffer + JC_TEST_SNPRINTF(buffer, buffer_len, "%s", ResultToString(r));
}

static Result ReturnFail() {
    return RESULT_FAIL;
}

TEST(Example, CustomPrint) {
    ASSERT_EQ(RESULT_OK, ReturnFail());
}

int main(int argc, char **argv)
{
    jc_test_init(&argc, argv);
    return jc_test_run_all();
}
# Compile the app
$ clang++ -I src hugo/static/code/example_custom_print.cpp

# Run the app
$ ./a.out
Last updated on