110 lines
3.5 KiB
C
110 lines
3.5 KiB
C
|
|
/**
|
||
|
|
* @file testutil.h
|
||
|
|
* @brief Shared assertions for the akbasic CTest programs.
|
||
|
|
*
|
||
|
|
* A test passes by exiting zero and fails by exiting non-zero with something
|
||
|
|
* informative on stderr.
|
||
|
|
*
|
||
|
|
* TEST_ASSERT and friends expand to a `break`, so they belong directly inside an
|
||
|
|
* ATTEMPT block, never inside a loop nested in one -- the same rule that governs
|
||
|
|
* CATCH and the FAIL_*_BREAK macros. TEST_REQUIRE is the return-based form for
|
||
|
|
* use inside loops and outside ATTEMPT blocks.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef _AKBASIC_TESTUTIL_H_
|
||
|
|
#define _AKBASIC_TESTUTIL_H_
|
||
|
|
|
||
|
|
#include <math.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#include <akerror.h>
|
||
|
|
|
||
|
|
/** Count of failures recorded by TEST_REQUIRE; main() returns it. */
|
||
|
|
static int akbasic_test_failures = 0;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Mark an error handled and hand it back to the pool. Assigning the result is
|
||
|
|
* what satisfies AKERR_NOIGNORE -- a (void) cast does not, and libakerror's
|
||
|
|
* IGNORE() would log to stderr and pollute the test output.
|
||
|
|
*/
|
||
|
|
static void test_discard_error(akerr_ErrorContext *e)
|
||
|
|
{
|
||
|
|
akerr_ErrorContext *released = NULL;
|
||
|
|
|
||
|
|
if ( e == NULL ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
e->handled = true;
|
||
|
|
released = akerr_release_error(e);
|
||
|
|
(void)released;
|
||
|
|
}
|
||
|
|
|
||
|
|
#define TEST_REQUIRE(__cond, ...) \
|
||
|
|
do { \
|
||
|
|
if ( !(__cond) ) { \
|
||
|
|
fprintf(stderr, "%s:%d: FAIL: ", __FILE__, __LINE__); \
|
||
|
|
fprintf(stderr, __VA_ARGS__); \
|
||
|
|
fprintf(stderr, "\n"); \
|
||
|
|
akbasic_test_failures += 1; \
|
||
|
|
} \
|
||
|
|
} while ( 0 )
|
||
|
|
|
||
|
|
#define TEST_REQUIRE_STR(__got, __want) \
|
||
|
|
TEST_REQUIRE(strcmp((__got), (__want)) == 0, \
|
||
|
|
"expected \"%s\", got \"%s\"", (__want), (__got))
|
||
|
|
|
||
|
|
#define TEST_REQUIRE_INT(__got, __want) \
|
||
|
|
TEST_REQUIRE((long long)(__got) == (long long)(__want), \
|
||
|
|
"expected %lld, got %lld", \
|
||
|
|
(long long)(__want), (long long)(__got))
|
||
|
|
|
||
|
|
#define TEST_REQUIRE_FEQ(__got, __want) \
|
||
|
|
TEST_REQUIRE(fabs((double)(__got) - (double)(__want)) < 1e-9, \
|
||
|
|
"expected %f, got %f", (double)(__want), (double)(__got))
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Assert that a call succeeded. Releases the context on failure so the pool does
|
||
|
|
* not drain across a long test.
|
||
|
|
*/
|
||
|
|
#define TEST_REQUIRE_OK(__call) \
|
||
|
|
do { \
|
||
|
|
akerr_ErrorContext *__e = (__call); \
|
||
|
|
if ( __e != NULL && __e->status != 0 ) { \
|
||
|
|
fprintf(stderr, "%s:%d: FAIL: %s: unexpected error %d (%s): %s\n", \
|
||
|
|
__FILE__, __LINE__, #__call, __e->status, \
|
||
|
|
akerr_name_for_status(__e->status, NULL), __e->message); \
|
||
|
|
akbasic_test_failures += 1; \
|
||
|
|
} \
|
||
|
|
test_discard_error(__e); \
|
||
|
|
} while ( 0 )
|
||
|
|
|
||
|
|
/** Assert that a call failed with a specific status. */
|
||
|
|
#define TEST_REQUIRE_STATUS(__call, __status) \
|
||
|
|
do { \
|
||
|
|
akerr_ErrorContext *__e = (__call); \
|
||
|
|
if ( __e == NULL || __e->status != (__status) ) { \
|
||
|
|
fprintf(stderr, "%s:%d: FAIL: %s: expected status %d (%s), got %d\n", \
|
||
|
|
__FILE__, __LINE__, #__call, (int)(__status), \
|
||
|
|
akerr_name_for_status((__status), NULL), \
|
||
|
|
(__e == NULL ? 0 : __e->status)); \
|
||
|
|
akbasic_test_failures += 1; \
|
||
|
|
} \
|
||
|
|
test_discard_error(__e); \
|
||
|
|
} while ( 0 )
|
||
|
|
|
||
|
|
/** Assert that a call failed, without caring which status. */
|
||
|
|
#define TEST_REQUIRE_ANY_ERROR(__call) \
|
||
|
|
do { \
|
||
|
|
akerr_ErrorContext *__e = (__call); \
|
||
|
|
if ( __e == NULL || __e->status == 0 ) { \
|
||
|
|
fprintf(stderr, "%s:%d: FAIL: %s: expected an error, got success\n", \
|
||
|
|
__FILE__, __LINE__, #__call); \
|
||
|
|
akbasic_test_failures += 1; \
|
||
|
|
} \
|
||
|
|
test_discard_error(__e); \
|
||
|
|
} while ( 0 )
|
||
|
|
|
||
|
|
#endif // _AKBASIC_TESTUTIL_H_
|