mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-30 00:23:24 +00:00
Add a framework for regression tests
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
e8a991048f
commit
b53980da25
164
regression/apps/network/test.h
Normal file
164
regression/apps/network/test.h
Normal file
@ -0,0 +1,164 @@
|
||||
/* SPDX-License-Identifier: MPL-2.0 */
|
||||
|
||||
/*
|
||||
* A framework for writing regression tests.
|
||||
*
|
||||
* A regression test typically consists of two parts, the setup part and the
|
||||
* test part. The setup part contains setup functions that set up the context
|
||||
* for the subsequent tests to run. The setup functions cannot fail, and if they
|
||||
* do, execution is aborted because the subsequent tests will not work as
|
||||
* expected either. The test functions, on the other hand, can fail, and if they
|
||||
* do, they are reported as test failures.
|
||||
*
|
||||
* The framework provides basic utilities for writing regression tests:
|
||||
*
|
||||
* - To define a setup function or a test function, FN_SETUP() or FN_TEST() can
|
||||
* be used. These functions are automatically executed in the order of their
|
||||
* definiton. Note that the order of execution is _not_ related to whether a
|
||||
* function is a setup function or a test function.
|
||||
*
|
||||
* - Within a setup function, CHECK() can be used to write a setup expression
|
||||
* that must succeed. If the expression fails, a fatal error will be reported
|
||||
* and the execution will be aborted.
|
||||
*
|
||||
* - Within a test function, TEST_SUCC() can be used to write a test expression
|
||||
* that should succeed. If the expression fails, a test failure will be reported
|
||||
* but the execution will continue.
|
||||
*
|
||||
* - The number of successful and failed tests is tracked. When a test function
|
||||
* finishes, a summary sentence is printed describing the number of test
|
||||
* failures. The program will exit with a non-zero code if and only if there is
|
||||
* at least one test failure.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/** Starts the definition of a setup function. */
|
||||
#define FN_SETUP(name) \
|
||||
void setup_##name(void) __attribute__((constructor(__LINE__ + 200))); \
|
||||
\
|
||||
void setup_##name(void) \
|
||||
{
|
||||
/** Ends the definition of a setup function. */
|
||||
#define END_SETUP() }
|
||||
|
||||
#define __CHECK(func, cond) \
|
||||
errno = 0; \
|
||||
long _ret = (func); \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, \
|
||||
"fatal error: %s: `" #cond "` is false after `" #func \
|
||||
"` [got %s]\n", \
|
||||
__func__, strerror(errno)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a fucntion call and checks its return value is positive.
|
||||
*
|
||||
* The execution will be aborted if the check fails.
|
||||
*/
|
||||
#define CHECK(func) \
|
||||
({ \
|
||||
__CHECK(func, _ret >= 0); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
/**
|
||||
* Makes a function call and checks its result with the specified condition.
|
||||
*
|
||||
* The execution will be aborted if the check fails.
|
||||
*
|
||||
* The return value of the function can be accessed with a local variable named
|
||||
* _ret.
|
||||
*/
|
||||
#define CHECK_WITH(func, cond) \
|
||||
({ \
|
||||
__CHECK(func, cond); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
static int __total_failures;
|
||||
|
||||
/** Starts the definition of a test function. */
|
||||
#define FN_TEST(name) \
|
||||
void test_##name(void) __attribute__((constructor(__LINE__ + 200))); \
|
||||
\
|
||||
void test_##name(void) \
|
||||
{ \
|
||||
int __tests_passed = 0, __tests_failed = 0;
|
||||
|
||||
/** Ends the definition of a test function. */
|
||||
#define END_TEST() \
|
||||
fprintf(stderr, "%s summary: %d tests passed, %d tests failed\n", \
|
||||
__func__, __tests_passed, __tests_failed); \
|
||||
__total_failures += __tests_failed; \
|
||||
}
|
||||
|
||||
#define __TEST(func, err, cond) \
|
||||
errno = 0; \
|
||||
long _ret = (func); \
|
||||
if (errno != (err)) { \
|
||||
__tests_failed++; \
|
||||
fprintf(stderr, \
|
||||
"%s: `" #func "` failed [got %s, but expected %s]\n", \
|
||||
__func__, strerror(errno), strerror(err)); \
|
||||
} else if (!(cond)) { \
|
||||
__tests_failed++; \
|
||||
fprintf(stderr, \
|
||||
"%s: `" #func "` failed [got %s, but `" #cond \
|
||||
"` is false]\n", \
|
||||
__func__, strerror(errno)); \
|
||||
} else { \
|
||||
__tests_passed++; \
|
||||
fprintf(stderr, "%s: `" #func "` passed [got %s]\n", __func__, \
|
||||
strerror(errno)); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a function call and checks its result.
|
||||
*
|
||||
* A test failure will be reported if the function does not set the specified
|
||||
* errno or the specified condition does not meet.
|
||||
*
|
||||
* The return value of the function can be accessed with a local variable named
|
||||
* _ret.
|
||||
*/
|
||||
#define TEST(func, err, cond) \
|
||||
({ \
|
||||
__TEST(func, err, cond); \
|
||||
_ret; \
|
||||
})
|
||||
/**
|
||||
* Makes a function call and checks whether it succeeds.
|
||||
*
|
||||
* A test failure will be reported if the function sets a non-zero errno.
|
||||
*/
|
||||
#define TEST_SUCC(func) TEST(func, 0, 1)
|
||||
|
||||
/**
|
||||
* Makes a function call and checks whether it fails in the specified way.
|
||||
*
|
||||
* A test failure will be reported if the function does not set the specified
|
||||
* errno.
|
||||
*/
|
||||
#define TEST_ERRNO(func, err) TEST(func, err, 1)
|
||||
|
||||
/**
|
||||
* Makes a function call and checks whether it produces expected results.
|
||||
*
|
||||
* A test failure will be reported if the function sets a non-zero errno or the
|
||||
* specified condition does not meet.
|
||||
*
|
||||
* The return value of the function can be accessed with a local variable named
|
||||
* _ret.
|
||||
*/
|
||||
#define TEST_RES(func, cond) TEST(func, 0, cond)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return __total_failures ? 1 : 0;
|
||||
}
|
Reference in New Issue
Block a user