Criterion Testing Framework

Overview

Qualified supports the Criterion testing framework.

Basic Example

Solution code

#include <stdlib.h>
#include <string.h>

char *reverse(const char *s) {
    int len = strlen(s);
    char *result = malloc(len + 1);
    result[len] = '\0';

    for (int i = 0; i < len; i++) {
        result[i] = s[len-1-i];
    }

    return result;
}

Test suite code

#include <criterion/criterion.h>
#include <stdlib.h>

extern char *reverse(const char *s);

Test(reverse, example_test) {
    char *actual = reverse("hello world");
    const char *expected = "dlrow olleh";
    cr_assert_str_eq(actual, expected);
    free(actual);
}

Verbose output for complex data

A potential for confusion when using Criterion is lack of verbosity in output. When comparing data structures, consider writing a stringification helper and passing it into the optional format parameter to Criterion's assertion call.

To illustrate the problem, consider that cr_assert_arr_eq(actual, expected, sizeof(expected)); by default produces an error The expression (actual)[0..Size] == (expected)[0..Size] is false. which doesn't show a diff of the two arrays. Adding an array stringification function allows for a much clearer error log. Here's a complete example:

Preloaded code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *arr_to_s(int len, int *arr) {
    int result_capacity = 8;
    int result_len = 0;
    char *result = malloc(result_capacity);

    if (!result) {
        fprintf(stderr, "%s:%d: malloc failed", __FILE__, __LINE__);
        exit(1);
    }

    result[0] = '\0';

    for (int i = 0; i < len; i++) {
        char num[16];
        result_len += sprintf(num, i < len - 1 ? "%d," : "%d", arr[i]);

        if (result_len >= result_capacity &&
            !(result = realloc(result, (result_capacity *= 2)))) {
            fprintf(stderr, "%s:%d: realloc failed", __FILE__, __LINE__);
            exit(1);
        }

        strcat(result, num);
    }

    return result;
}

Solution code

#include <stdlib.h>

int *reverse(const int len, const int *nums) {
    int *result = malloc(sizeof(*result) * len);

    for (int i = 0; i < len; i++) {
        result[i] = nums[len-1-i];
    }

    return result;
}

Test suite code

#include <criterion/criterion.h>
#include <stdlib.h>

extern char *arr_to_s(int len, int *arr);
extern int *reverse(int len, int *nums);

Test(split_integer, reverse_test) {
    int nums[] = {1, 2, 3};
    int expected[] = {3, 2, 1};
    int len = sizeof nums / sizeof nums[0];
    int *actual = reverse(len, nums);
    char *expected_s = arr_to_s(len, expected);
    char *actual_s = arr_to_s(len, actual);
    cr_assert_arr_eq(actual, expected, sizeof(expected), 
                     "expected [%s] but got [%s]", expected_s, actual_s);
    free(expected_s);
    free(actual_s);
    free(actual);
};

Now, when the candidate fails a test, the log shows the arrays in a more helpful format like expected [3,2,1] but got [42,2,1].