blob: 5dffd06e302d5322578288f703d677004d9a99f2 [file] [log] [blame]
/*
* Copyright (c) 2013-2015, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PTUNIT_H__
#define __PTUNIT_H__
#include <stdint.h>
#include <string.h>
/* A source location for reporting unit test fails. */
struct ptunit_srcloc {
/* The source file. */
const char *file;
/* The source line. */
uint32_t line;
};
/* A unit test result type.
*
* This distinguishes the various potential results of a unit test.
*/
enum ptunit_result_type {
/* The test has passed. */
ptur_passed,
/* The test has been skipped. */
ptur_skipped,
/* The test failed a signed/unsigned integer comparison. */
ptur_failed_signed_int,
ptur_failed_unsigned_int,
/* The test failed a pointer comparison. */
ptur_failed_pointer,
/* The test failed a string comparison. */
ptur_failed_str
};
/* A unit test result.
*
* We separate test execution and result reporting. A unit test function
* returns a structured result that can later be used for reporting.
*/
struct ptunit_failed_signed_int {
/* The expression that failed. */
const char *expr;
/* A string representation of the comparison operation. */
const char *cmp;
/* The expected value. */
int64_t expected;
/* The actual value. */
int64_t actual;
};
struct ptunit_failed_unsigned_int {
/* The expression that failed. */
const char *expr;
/* A string representation of the comparison operation. */
const char *cmp;
/* The expected value. */
uint64_t expected;
/* The actual value. */
uint64_t actual;
};
struct ptunit_failed_pointer {
/* The expression that failed. */
const char *expr;
/* A string representation of the comparison operation. */
const char *cmp;
/* The expected value. */
const void *expected;
/* The actual value. */
const void *actual;
};
struct ptunit_failed_str {
/* The expression that failed. */
const char *expr;
/* A string representation of the comparison operation. */
const char *cmp;
/* The expected value. */
char *expected;
/* The actual value. */
char *actual;
};
struct ptunit_result {
/* The test result type. */
enum ptunit_result_type type;
/* Test result details depending on the result type. */
struct {
/* The source location of the fail. */
struct ptunit_srcloc where;
union {
struct ptunit_failed_signed_int signed_int;
struct ptunit_failed_unsigned_int unsigned_int;
struct ptunit_failed_pointer pointer;
struct ptunit_failed_str str;
} variant;
} failed;
};
/* A unit test function. */
typedef struct ptunit_result (*ptunit_tfun_t)(void);
/* A unit test.
*
* This is used for logging and reporting.
*
* It is not used for running tests or even for storing tests to be run at a
* later time.
*/
struct ptunit_test {
/* The test name. */
const char *name;
/* The optional test arguments. */
const char *args;
/* The test result. */
struct ptunit_result result;
};
/* A unit test suite.
*
* This is a simple summary of all tests that have been run.
*/
struct ptunit_suite {
/* An optional suite name. */
const char *name;
/* The number of total tests. */
uint32_t nr_tests;
/* The number of tests that have been skipped. */
uint32_t nr_skips;
/* The number of tests that have failed. */
uint32_t nr_fails;
};
/* Create a unit test source location. */
extern struct ptunit_srcloc ptunit_mk_srcloc(const char *file, uint32_t line);
#define ptu_here() ptunit_mk_srcloc(__FILE__, __LINE__)
/* Create unit test passed and not run results. */
extern struct ptunit_result ptunit_mk_passed(void);
extern struct ptunit_result ptunit_mk_skipped(void);
/* Create a unit test failed signed int result. */
extern struct ptunit_result ptunit_mk_failed_signed_int(const char *expr,
const char *cmp,
struct ptunit_srcloc,
int64_t actual,
int64_t expected);
#define ptunit_int_cmp(A, E, C) \
do { \
int64_t __a = (A), __e = (E); \
\
if (!(__a C __e)) \
return ptunit_mk_failed_signed_int(#A #C #E, #C, \
ptu_here(), \
__a, __e); \
} while (0)
/* Create a unit test failed unsigned int result. */
extern struct ptunit_result ptunit_mk_failed_unsigned_int(const char *expr,
const char *cmp,
struct ptunit_srcloc,
int64_t actual,
int64_t expected);
#define ptunit_uint_cmp(A, E, C) \
do { \
uint64_t __a = (A), __e = (E); \
\
if (!(__a C __e)) \
return ptunit_mk_failed_unsigned_int(#A #C #E, #C, \
ptu_here(), \
__a, __e); \
} while (0)
/* Create a unit test failed pointer result. */
extern struct ptunit_result ptunit_mk_failed_pointer(const char *expr,
const char *cmp,
struct ptunit_srcloc,
const void *actual,
const void *expected);
#define ptunit_ptr_cmp(A, E, C) \
do { \
const void *__a = (A), *__e = (E); \
\
if (!(__a C __e)) \
return ptunit_mk_failed_pointer(#A #C #E, #C, \
ptu_here(), \
__a, __e); \
} while (0)
/* Create a unit test failed string result. */
extern struct ptunit_result ptunit_mk_failed_str(const char *expr,
const char *cmp,
struct ptunit_srcloc,
const char *actual,
const char *expected);
#define ptunit_str_cmp(A, E, C) \
do { \
const char *__a = (A), *__e = (E); \
\
ptunit_ptr_cmp(A, NULL, !=); \
ptunit_ptr_cmp(E, NULL, !=); \
\
if (!(strcmp(__a, __e) C 0)) \
return ptunit_mk_failed_str(#A "~"#C #E, "~"#C, \
ptu_here(), \
__a, __e); \
} while (0)
/* Run a sub-unit test; return on fail. */
#define ptunit_subtest(T, ...) \
do { \
struct ptunit_result __result; \
\
__result = (T)(__VA_ARGS__); \
if (__result.type != ptur_passed) \
return __result; \
} while (0)
/* Run a sub-unit test; return on fail from here. */
#define ptunit_check(T, ...) \
do { \
struct ptunit_result __result; \
\
__result = (T)(__VA_ARGS__); \
if (__result.type != ptur_passed) { \
__result.failed.where = ptu_here(); \
return __result; \
} \
} while (0)
/* Create a unit test. */
extern struct ptunit_test ptunit_mk_test(const char *name, const char *args);
/* Destroy a unit test. */
extern void ptunit_fini_test(struct ptunit_test *);
/* Create a unit test suite. */
extern struct ptunit_suite ptunit_mk_suite(int argc, char **argv);
/* Log a unit test result.
*
* This may also report test fails depending on the configuration.
*/
extern void ptunit_log_test(struct ptunit_suite *, const struct ptunit_test *);
/* Print a summary report for a unit test suite. */
extern void ptunit_report(const struct ptunit_suite *);
/* Run a single simple unit test and log its result. */
#define ptunit_run(S, T) \
do { \
struct ptunit_test __test; \
\
__test = ptunit_mk_test(#T, NULL); \
__test.result = (T)(); \
\
ptunit_log_test(S, &__test); \
ptunit_fini_test(&__test); \
} while (0)
/* Run a single parameterized unit test and log its result. */
#define ptunit_run_p(S, T, ...) \
do { \
struct ptunit_test __test; \
\
__test = ptunit_mk_test(#T, #__VA_ARGS__); \
__test.result = (T)(__VA_ARGS__); \
\
ptunit_log_test(S, &__test); \
ptunit_fini_test(&__test); \
} while (0)
/* Run a single unit test with fixture and an explict argument list.
*
* The first argument in the argument list is typically the fixture.
*/
#define ptunit_frun(R, T, F, ...) \
do { \
struct ptunit_result *__pr = &(R); \
\
__pr->type = ptur_passed; \
if ((F)->init) \
*__pr = (F)->init(F); \
\
if (__pr->type == ptur_passed) \
*__pr = (T)(__VA_ARGS__); \
\
if ((F)->fini) { \
if (__pr->type == ptur_passed) \
*__pr = (F)->fini(F); \
else \
(void) (F)->fini(F); \
} \
} while (0)
/* Run a single unit test with fixture and log its result. */
#define ptunit_run_f(S, T, F) \
do { \
struct ptunit_test __test; \
\
__test = ptunit_mk_test(#T, #F); \
\
ptunit_frun(__test.result, T, &(F), &(F)); \
\
ptunit_log_test(S, &__test); \
ptunit_fini_test(&__test); \
} while (0)
/* Run a single parameterized unit test with fixture and log its result. */
#define ptunit_run_fp(S, T, F, ...) \
do { \
struct ptunit_test __test; \
\
__test = ptunit_mk_test(#T, #F ", " #__VA_ARGS__); \
\
ptunit_frun(__test.result, T, &(F), &(F), __VA_ARGS__); \
\
ptunit_log_test(S, &__test); \
ptunit_fini_test(&__test); \
} while (0)
/* The actual macros to be used in unit tests.
*
* Do not use the above ptunit_ macros directly.
*/
#define ptu_int_eq(A, E) ptunit_int_cmp(A, E, ==)
#define ptu_int_ne(A, E) ptunit_int_cmp(A, E, !=)
#define ptu_int_gt(A, E) ptunit_int_cmp(A, E, >)
#define ptu_int_ge(A, E) ptunit_int_cmp(A, E, >=)
#define ptu_int_lt(A, E) ptunit_int_cmp(A, E, <)
#define ptu_int_le(A, E) ptunit_int_cmp(A, E, <=)
#define ptu_uint_eq(A, E) ptunit_uint_cmp(A, E, ==)
#define ptu_uint_ne(A, E) ptunit_uint_cmp(A, E, !=)
#define ptu_uint_gt(A, E) ptunit_uint_cmp(A, E, >)
#define ptu_uint_ge(A, E) ptunit_uint_cmp(A, E, >=)
#define ptu_uint_lt(A, E) ptunit_uint_cmp(A, E, <)
#define ptu_uint_le(A, E) ptunit_uint_cmp(A, E, <=)
#define ptu_ptr_eq(A, E) ptunit_ptr_cmp(A, E, ==)
#define ptu_ptr_ne(A, E) ptunit_ptr_cmp(A, E, !=)
#define ptu_ptr_gt(A, E) ptunit_ptr_cmp(A, E, >)
#define ptu_ptr_ge(A, E) ptunit_ptr_cmp(A, E, >=)
#define ptu_ptr_lt(A, E) ptunit_ptr_cmp(A, E, <)
#define ptu_ptr_le(A, E) ptunit_ptr_cmp(A, E, <=)
#define ptu_null(A) ptunit_ptr_cmp(A, NULL, ==)
#define ptu_ptr(A) ptunit_ptr_cmp(A, NULL, !=)
#define ptu_str_eq(A, E) ptunit_str_cmp(A, E, ==)
#define ptu_str_ne(A, E) ptunit_str_cmp(A, E, !=)
/* Indicate that a unit test passed. */
#define ptu_passed() ptunit_mk_passed()
/* Skip a unit test. */
#define ptu_skipped() ptunit_mk_skipped()
/* Run a sub-unit test; return on fail. */
#define ptu_test(T, ...) ptunit_subtest(T, __VA_ARGS__)
/* Run a sub-unit test; return on fail from here. */
#define ptu_check(T, ...) ptunit_check(T, __VA_ARGS__)
/* Run a single unit test. */
#define ptu_run(S, T) ptunit_run(&(S), T)
/* Run a single parameterized unit test. */
#define ptu_run_p(S, T, ...) ptunit_run_p(&(S), T, __VA_ARGS__)
/* Run a single unit test with fixture. */
#define ptu_run_f(S, T, F) ptunit_run_f(&(S), T, F)
/* Run a single parameterized unit test with fixture. */
#define ptu_run_fp(S, T, F, ...) ptunit_run_fp(&(S), T, F, __VA_ARGS__)
#endif /* __PTUNIT_H__ */