blob: f650d3a9ac163475f593f42506203a5ccca6ea60 [file]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <inttypes.h>
#include <lk/compiler.h>
#include <lk/list.h>
#include <stdbool.h>
#include <string.h>
__BEGIN_CDECLS
/*
* This function returns a time in nanoseconds based on hardware counters
* it is expected to:
* - Be non-wrapping or have very long (years) roll-over period
* - Have a resolution below 100nsc
*/
uint64_t get_current_time_ns(void);
/*
* Test functions can be defined with:
* TEST(SuiteName, TestName) {
* ... test body ...
* }
* or with:
* TEST_F(SuiteName, TestName) {
* ... test body ...
* }
* or with:
* TEST_P(SuiteName, TestName) {
* ... test body ...
* }
*
* NOTE: SuiteName and TestName should not contain underscores.
*
* Use EXPECT_<op> or ASSERT_<op> directly in test functions or from nested
* functions to check test conditions. Where <op> can be:
* EQ for ==
* NE for !=
* LT for <
* LE for <=
* GT for >
* GE for >=
*
* The test functions follows this pattern:
* <EXPECT|ASSERT>_<op>(val1, val2 [, format, ...])
* If val1 <op> val2 is not true, then both values will be printed and a test
* failure will be recorded. For ASSERT_<op> it will also jump to a test_abort
* label in the calling function.
*
* Call RUN_ALL_TESTS() to run all tests defined by TEST (or
* RUN_ALL_SUITE_TESTS("SuiteName") to only run tests with the specified
* SuiteName). RUN_ALL_TESTS and RUN_ALL_SUITE_TESTS return true if all the
* tests passed.
*
* Test functions defined with TEST_F or TEST_P expect the type <SuiteName>_t
* and <SuiteName>_SetUp and <SuiteName>_TearDown functions to be defined.
* The <SuiteName>_SetUp function will be called once before each test in
* SuiteName in run and the <SuiteName>_TearDown function will be called once
* after each test in SuiteName is run. These functions can be defined with
* TEST_F_SETUP(<SuiteName>) {
* ... setup body ...
* }
* and with:
* TEST_F_TEARDOWN(<SuiteName>) {
* ... teardown body ...
* }
* A pointer to a <SuiteName>_t variable will be passed as "_state" to the
* setup, teardown and test functions.
*
* TEST_FIXTURE_ALIAS(NewSuiteName, OldSuiteName) can be used to use the test
* fixture defined for OldSuiteName with NewSuiteName.
*
* Tests defined with TEST_P will only run when their suite is run if they have
* been instantiated with parameters using INSTANTIATE_TEST_SUITE_P. These tests
* can access their parameter using GetParam()
*/
#ifndef trusty_unittest_printf
#error trusty_unittest_printf must be defined
#endif
/**
* struct test_context - struct representing the state of a test run.
* @tests_total: Number of conditions checked
* @tests_skipped: Number of tests skipped
* @tests_disabled: Number of disabled tests skipped
* @tests_failed: Number of conditions failed
* @inst_name: Name of the current parameter instantiation
* @suite_name: Name of the current test suite
* @param_name: Name of the current parameter
* @test_name: Name of current test case
* @test_param: The current test parameter
* @all_ok: State of current test case
* @skipped: Current test was skipped.
* @hard_fail: Type of test failure (when @all_ok is false)
* @test_start_time: Test Start Time in ns
* @suite_duration_ms:Test Suite duration in ms
*/
struct test_context {
unsigned int tests_total;
unsigned int tests_skipped;
unsigned int tests_disabled;
unsigned int tests_failed;
const char* inst_name;
const char* suite_name;
const char* param_name;
const char* test_name;
const void* test_param;
bool all_ok;
bool skipped;
bool hard_fail;
uint64_t test_start_time;
uint64_t suite_duration_ms;
};
/**
* struct test_list_node - node to hold test function in list of tests
* @node: List node
* @suite: Name of test suite (optionally used for filtering)
* @name: Name of test (optionally used for filtering)
* @func: Test function
* @needs_param: Indicates if the test function is parameterized
*/
struct test_list_node {
struct list_node node;
const char* suite;
const char* name;
void (*func)(void);
bool needs_param;
};
/**
* struct test_param_gen - struct representing a parameter generator
* @gen_param: Function to generate the parameter for a test
* @priv: Private data passed to gen_param
*/
struct test_param_gen {
const void* (*gen_param)(void*, int);
void* priv;
};
/**
* typedef test_param_to_string_t - Converts a test parameter to its string form
* @param: Parameter to convert
* @buf: Buffer to fill with a NULL terminated string representation of
* @param
* @buf_size: Size in bytes of @buf
*
* When called, this function is passed a pointer to the parameter for the test
* that is being executed in @param and must return a null-terminated string
* representing the passed in parameter in @buf of at most size @buf_size.
*/
typedef void (*test_param_to_string_t)(const void* param,
char* buf,
size_t buf_size);
/**
* struct test_param_list_node - holds parameter generators
* @node: List node
* @param_gen: Parameter generator
* @to_string: Function to convert a parameter to its string form
* @inst_name: Name of the instantiation associated with the generator
* @suite: Name of test suite associated with the generator
*/
struct test_param_list_node {
struct list_node node;
struct test_param_gen param_gen;
test_param_to_string_t to_string;
const char* inst_name;
const char* suite;
};
static struct test_context _test_context;
/*
* List of tests. Tests are added by a __attribute__((constructor)) function
* per test defined by the TEST macro.
*/
static struct list_node _test_list = LIST_INITIAL_VALUE(_test_list);
/*
* List of parameter generators. Parameter generators are added by a
* __attribute__((constructor)) function per instantiation defined with
* INSTANTIATE_TEST_SUITE_P.
*/
static struct list_node _test_param_list = LIST_INITIAL_VALUE(_test_param_list);
static inline void trusty_unittest_print_status_name_param_duration(
const char* status,
const char* param_gen_inst_name, /* parameter generator instance name */
const char* suite_name,
const char* test_name,
const char* param_name,
const char* duration_ms) {
if (param_gen_inst_name) {
trusty_unittest_printf("[ %s ] %s/%s.%s/%s%s\n", status,
param_gen_inst_name, suite_name, test_name,
param_name, duration_ms);
} else {
trusty_unittest_printf("[ %s ] %s.%s%s\n", status, suite_name,
test_name, duration_ms);
}
}
static inline void trusty_unittest_print_status_name(const char* suite_name,
const char* test_name,
const char* status) {
trusty_unittest_print_status_name_param_duration(
status, _test_context.inst_name, suite_name, test_name,
_test_context.param_name, "");
}
static inline void trusty_unittest_print_status(const char* status) {
trusty_unittest_print_status_name_param_duration(
status, _test_context.inst_name, _test_context.suite_name,
_test_context.test_name, _test_context.param_name, "");
}
static inline void trusty_unittest_print_status_duration(
const char* status,
uint64_t test_duration_ms) {
char duration_str[16] = "";
/* print duration at end of test case */
snprintf(duration_str, sizeof(duration_str), " (%" PRIu64 " ms)",
test_duration_ms);
trusty_unittest_print_status_name_param_duration(
status, _test_context.inst_name, _test_context.suite_name,
_test_context.test_name, _test_context.param_name,
(const char*)duration_str);
}
static inline void TEST_BEGIN_FUNC(const char* suite_name,
const char* test_name) {
_test_context.suite_name = suite_name;
_test_context.test_name = test_name;
_test_context.all_ok = true;
_test_context.hard_fail = false;
_test_context.skipped = false;
_test_context.tests_total++;
trusty_unittest_print_status("RUN ");
/*
* initialize the test start time
* (after the print status is slightly better)
*/
_test_context.test_start_time = get_current_time_ns();
}
static inline void TEST_END_FUNC(void) {
uint64_t test_duration_ms =
(get_current_time_ns() - _test_context.test_start_time) / 1000000;
_test_context.suite_duration_ms += test_duration_ms;
if (_test_context.skipped) {
trusty_unittest_print_status_duration(" SKIPPED", test_duration_ms);
} else if (_test_context.all_ok) {
trusty_unittest_print_status_duration(" OK", test_duration_ms);
} else {
trusty_unittest_print_status_duration(" FAILED ", test_duration_ms);
}
_test_context.test_name = NULL;
}
#define STRINGIFY(x) #x
#define TEST_FIXTURE_ALIAS(new_suite_name, old_suite_name) \
typedef old_suite_name##_t new_suite_name##_t; \
\
static void new_suite_name##_SetUp(new_suite_name##_t* _state) { \
old_suite_name##_SetUp(_state); \
} \
static void new_suite_name##_TearDown(new_suite_name##_t* _state) { \
old_suite_name##_TearDown(_state); \
}
#define TEST_INTERNAL(suite_name, test_name, w_param, pre, post, arg, argp) \
static void suite_name##_##test_name##_inner argp; \
\
static void suite_name##_##test_name(void) { \
TEST_BEGIN_FUNC(STRINGIFY(suite_name), STRINGIFY(test_name)); \
{ \
pre; \
if (!_test_context.hard_fail && !_test_context.skipped) { \
suite_name##_##test_name##_inner arg; \
} \
post; \
} \
TEST_END_FUNC(); \
} \
\
static struct test_list_node suite_name##_##test_name##_node = { \
.node = LIST_INITIAL_CLEARED_VALUE, \
.suite = #suite_name, \
.name = #test_name, \
.func = suite_name##_##test_name, \
.needs_param = w_param, \
}; \
\
__attribute__((constructor)) void suite_name##_##test_name##_add(void) { \
list_add_tail(&_test_list, &suite_name##_##test_name##_node.node); \
} \
\
static void suite_name##_##test_name##_inner argp
#define TEST_F_SETUP(suite_name) \
static void suite_name##_SetUp(suite_name##_t* _state)
#define TEST_F_TEARDOWN(suite_name) \
static void suite_name##_TearDown(suite_name##_t* _state)
#define TEST(suite_name, test_name) \
TEST_INTERNAL(suite_name, test_name, false, , , (), (void))
#define TEST_F_CUSTOM_ARGS(suite_name, test_name, arg, argp) \
TEST_INTERNAL(suite_name, test_name, false, suite_name##_t state; \
suite_name##_SetUp(&state);, suite_name##_TearDown(&state); \
, arg, argp)
#define TEST_F(suite_name, test_name) \
TEST_F_CUSTOM_ARGS(suite_name, test_name, (&state), \
(suite_name##_t * _state))
#define TEST_P_CUSTOM_ARGS(suite_name, test_name, arg, argp) \
TEST_INTERNAL(suite_name, test_name, true, suite_name##_t state; \
suite_name##_SetUp(&state);, suite_name##_TearDown(&state); \
, arg, argp)
#define TEST_P(suite_name, test_name) \
TEST_P_CUSTOM_ARGS(suite_name, test_name, (&state), \
(suite_name##_t * _state))
struct test_array_param {
const void* arr;
int elem_size;
int count;
};
static inline const void* test_gen_array_param(void* priv, int i) {
struct test_array_param* param = (struct test_array_param*)priv;
if (i >= param->count) {
return NULL;
}
return (uint8_t*)param->arr + param->elem_size * i;
}
struct test_range_param {
long begin;
long end;
long step;
long current;
};
static inline const void* test_gen_range_param(void* priv, int i) {
struct test_range_param* range_param = (struct test_range_param*)priv;
range_param->current = range_param->begin + range_param->step * i;
if (range_param->current >= range_param->end) {
return NULL;
}
return &range_param->current;
}
struct combined_params {
struct test_param_gen* generators;
int generator_count;
int* idxs;
const void** current;
};
static inline void update_combined_params(struct combined_params* params,
int j,
bool reset) {
if (reset) {
params->idxs[j] = 0;
}
params->current[j] = params->generators[j].gen_param(
params->generators[j].priv, params->idxs[j]);
params->idxs[j]++;
}
static inline const void* test_gen_combined_param(void* priv, int i) {
struct combined_params* params = (struct combined_params*)priv;
if (i == 0) {
for (int j = 0; j < params->generator_count; j++) {
update_combined_params(params, j, true);
}
return params->current;
}
for (int j = 0; j < params->generator_count; j++) {
update_combined_params(params, j, false);
if (params->current[j] != NULL) {
return params->current;
}
update_combined_params(params, j, true);
}
return NULL;
}
#define FIRST_ARG(arg0, args...) arg0
#define SECOND_ARG(arg0, arg1, args...) arg1
/* Parentheses are used to prevent commas from being interpreted when they are
* passed in macro arguments. DELETE_PAREN is used to remove these parentheses
* inside the macro that uses the commas e.g.:
*
* MY_MACRO((1, 2, 3))
*
* #define MY_MACRO(arg)
* DELETE_PAREN arg
*/
#define DELETE_PAREN(args...) args
#define testing_Range(_begin, end_step...) \
(static struct test_range_param range_param = \
{ \
.begin = _begin, \
.end = FIRST_ARG(end_step, ), \
.step = SECOND_ARG(end_step, 1, ), \
}; \
param_node.param_gen.gen_param = test_gen_range_param; \
param_node.param_gen.priv = &range_param;)
#define testing_ValuesIn(array) \
(static struct test_array_param array_param = \
{ \
.arr = array, \
.elem_size = sizeof(array[0]), \
.count = countof(array), \
}; \
\
param_node.param_gen.gen_param = test_gen_array_param; \
param_node.param_gen.priv = &array_param;)
/*
* (args, args) is passed to __typeof__ to guarantee that it resolves to const
* char* instead of const char[] in cases where args contains a single string.
* When args is a single string, it is inlined and typeof will resolve to const
* char[].
*/
#define testing_Values(args...) \
(static __typeof__(args, args) new_arr[] = {args}; \
DELETE_PAREN testing_ValuesIn(new_arr))
#define testing_Bool() testing_Values(false, true)
#define test_set_combine_params(generator, i, count) \
{ \
DELETE_PAREN generator; \
if (i < count) { \
param_gens[i].gen_param = param_node.param_gen.gen_param; \
param_gens[i].priv = param_node.param_gen.priv; \
} \
}
#define testing_Combine_internal(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \
arg7, arg8, arg9, da0, da1, da2, da3, da4, \
da5, da6, da7, da8, da9, count, args...) \
(static struct test_param_gen param_gens[count]; static int idxs[count]; \
static const void* current_params[count]; \
static struct combined_params combined_params = \
{ \
param_gens, \
count, \
idxs, \
current_params, \
}; \
\
test_set_combine_params(arg0, 0, count); \
test_set_combine_params(arg1, 1, count); \
test_set_combine_params(arg2, 2, count); \
test_set_combine_params(arg3, 3, count); \
test_set_combine_params(arg4, 4, count); \
test_set_combine_params(arg5, 5, count); \
test_set_combine_params(arg6, 6, count); \
test_set_combine_params(arg7, 7, count); \
test_set_combine_params(arg8, 8, count); \
test_set_combine_params(arg9, 9, count); \
param_node.param_gen.gen_param = test_gen_combined_param; \
param_node.param_gen.priv = &combined_params;)
#define testing_Combine(generators...) \
testing_Combine_internal(generators, (), (), (), (), (), (), (), (), (), \
(), 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define INSTANTIATE_TEST_SUITE_P_INTERNAL(_inst_name, suite_name, param_gen, \
param_to_string, args...) \
\
__attribute__((constructor)) void suite_name##_##_inst_name##param_add( \
void) { \
static struct test_param_list_node param_node = { \
.node = LIST_INITIAL_CLEARED_VALUE, \
.to_string = param_to_string, \
.inst_name = STRINGIFY(_inst_name), \
.suite = #suite_name, \
}; \
\
DELETE_PAREN param_gen; \
\
list_add_tail(&_test_param_list, &param_node.node); \
}
static inline bool has_disabled_prefix(const char* str) {
const char disabled_prefix[] = "DISABLED_";
return strncmp(str, disabled_prefix, strlen(disabled_prefix)) == 0;
}
static inline bool trusty_unittest_test_is_disabled(
struct test_list_node* entry) {
return has_disabled_prefix(entry->suite) ||
has_disabled_prefix(entry->name);
}
/**
* trusty_unittest_count_param_entries - Count parameter entries for a given
* test suite.
*
* @suite: Name of test suite associated with the parameters
* suite is never going to be NULL (see invocation),
* no need to guard against this case.
*
* For each parameter generator associated with the suite, accrue
* the number of parameter entries.
*
* Not meant for external use.
*
* Return: count of parameter entries
*/
static int trusty_unittest_count_param_entries(
struct test_list_node* test_case) {
int param_count = 0;
int i;
struct test_param_list_node* param_entry;
bool has_param_gen = 0;
bool invalid_run = false;
/*
* for each parameter generator associated with the suite,
* accrue the number of parameter entries
*/
list_for_every_entry(&_test_param_list, param_entry,
struct test_param_list_node, node) {
if (!strcmp(test_case->suite, param_entry->suite)) {
i = 0;
has_param_gen = true;
/* For each parameter from the generator */
while (param_entry->param_gen.gen_param(param_entry->param_gen.priv,
i)) {
i++;
}
if (!i) {
/*
* No parameter entries: parameterized test case exist
* but the test generator is empty
*/
trusty_unittest_print_status_name_param_duration(
" FAILED ", param_entry->inst_name, test_case->suite,
test_case->name,
"NO PARAMS: Parameterized Test Case Generator without Params!",
"");
invalid_run = true;
}
param_count += i;
}
}
/*
* No parameter generator: parameterized test case exist
* but the test suite is not associated with any param generator
*/
if (!has_param_gen) {
trusty_unittest_print_status_name_param_duration(
" FAILED ", "NO PARAM GENERATOR", test_case->suite,
test_case->name,
"NO PARAMS: Parameterized Test Case without Param Generator!",
"");
}
return invalid_run ? 0 : param_count;
}
/**
* trusty_unittest_has_parameterized_test_case - test suite with parameterized
* test cases
*
* @suite: Name of test suite associated with the parameters.
* suite is never going to be NULL (see invocation),
* no need to guard against this case.
*
* Check whether a test suite has parameterized test cases.
* Not meant for external use.
*
* Return: True if parameterized test
*/
static bool trusty_unittest_has_parameterized_test_case(const char* suite) {
struct test_list_node* test_case;
list_for_every_entry(&_test_list, test_case, struct test_list_node, node) {
if (!strcmp(suite, test_case->suite)) {
if (test_case->needs_param) {
return true;
}
}
}
return false;
}
/**
* trusty_unittest_count_test_cases - Count test cases associated with test
* suite.
*
* @suite: Name of test suite.
* When suite is NULL, all test cases from all test suites are counted.
*
* This test case count shall comply to the GTest parser requirements
* and thus shall not include disabled test cases.
* Not meant for external use.
*
* Return: count of test cases, -1 in case of detected test suite coding error
*/
static int trusty_unittest_count_test_cases(const char* suite) {
struct test_list_node* test_case;
struct test_param_list_node* param_entry;
bool test_code_error = false;
size_t test_case_count = 0;
bool disabled;
int param_entries = 0;
const char* param_entries_suite = NULL;
int current_test_case_count;
/* count all non parameterized and parameterized test cases */
list_for_every_entry(&_test_list, test_case, struct test_list_node, node) {
/* exclude tests not part of the requested suite */
if (suite && strcmp(suite, test_case->suite)) {
continue;
}
/* only count non-disabled test case as required by the GTest parser */
disabled = trusty_unittest_test_is_disabled(test_case);
if (test_case->needs_param) {
if (!param_entries_suite || !param_entries ||
strcmp(param_entries_suite, test_case->suite)) {
/* count param_entries for test_case->suite */
param_entries = trusty_unittest_count_param_entries(test_case);
param_entries_suite = test_case->suite;
}
if (!param_entries) {
/*
* Test code error shall be fixed and will prevent test
* execution however we don't bail right away with the goal of
* logging all erroneous test cases.
*/
test_code_error = true;
continue;
}
current_test_case_count = param_entries;
} else {
current_test_case_count = 1;
}
if (!disabled) {
/* non parameterized (singular) test case */
test_case_count += current_test_case_count;
}
}
/*
* Search for a test coding issue where a test generator exists
* but is not backed by existing test case
*/
list_for_every_entry(&_test_param_list, param_entry,
struct test_param_list_node, node) {
if (!trusty_unittest_has_parameterized_test_case(param_entry->suite)) {
test_code_error = true;
trusty_unittest_print_status_name_param_duration(
" FAILED ", param_entry->inst_name, param_entry->suite,
"NO_TESTS", "Parameter Generator without tests!", "");
}
}
return test_code_error ? -1 : test_case_count;
}
/**
* trusty_unittest_run_test_suite - run each test case associated with test
* suite.
*
* @suite: Name of test suite
* when suite is NULL, all test cases
* from all test suites are executed.
* @needs_param: when true run the parameterised test cases,
* otherwise run the non-parameterised test cases
*
* Not meant for external use.
*
* Return: count of executed test cases
*/
static int trusty_unittest_run_test_suite(const char* suite, bool needs_param) {
struct test_list_node* entry;
int test_case_count = 0;
list_for_every_entry(&_test_list, entry, struct test_list_node, node) {
if ((!suite || !strcmp(suite, entry->suite)) &&
(entry->needs_param == needs_param)) {
if (trusty_unittest_test_is_disabled(entry)) {
trusty_unittest_print_status_name(entry->suite, entry->name,
"DISABLED");
_test_context.tests_disabled++;
} else {
test_case_count++;
entry->func();
}
}
}
return test_case_count;
}
/*
* The testing framework uses 3 global variables to keep track of tests and
* related data:
*
* _test_context: contains information about the overall execution of the
* framework (e.g. total tests run) and information about the currently
* executing test (e.g. test name, suite name).
*
* _test_list: contains a list of tests that can be run. Each test belongs to a
* test suite and may require parameters to be run.
*
* _test_param_list: contains a list of parameter generators for tests that
* require parameters. Each generator is associated with a specific test suite.
* Parameter generators are functions that return parameters that apply to all
* the tests that require parameters (i.e. parameterized tests) in a given test
* suite.
*
* Tests are only run as part of test suites. When a test suite is run all of
* the non-paremeterized tests belonging to that suite are run first followed by
* the parameterized tests in the suite. All of the parameterized tests in a
* suite are run once for each value returned by a parameter generator
* associated with that suite.
*/
static inline bool RUN_ALL_SUITE_TESTS(const char* suite) {
struct test_param_list_node* param_entry;
const void* test_param;
int i;
char param_str[64];
int actual_test_count = 0;
int expected_test_count = trusty_unittest_count_test_cases(suite);
if (expected_test_count == -1) {
trusty_unittest_printf("Test Coding Error - aborting execution.\n");
return false;
}
trusty_unittest_printf(
"[==========] Running %d tests from %s test suite%s.\n",
expected_test_count, suite ? suite : "all", suite ? "" : "s");
_test_context.tests_total = 0;
_test_context.tests_disabled = 0;
_test_context.tests_failed = 0;
_test_context.test_param = NULL;
_test_context.inst_name = NULL;
_test_context.param_name = param_str;
_test_context.suite_duration_ms = 0;
/* Run all the non-parameterized tests in the suite */
actual_test_count = trusty_unittest_run_test_suite(suite, false);
/* For each parameter generator associated with the suite */
list_for_every_entry(&_test_param_list, param_entry,
struct test_param_list_node, node) {
if (!suite || !strcmp(suite, param_entry->suite)) {
i = 0;
/* For each parameter from the generator */
while ((test_param = param_entry->param_gen.gen_param(
param_entry->param_gen.priv, i))) {
/* Set the parameter for the next run */
_test_context.inst_name = param_entry->inst_name;
_test_context.test_param = test_param;
if (param_entry->to_string) {
param_entry->to_string(test_param, param_str,
sizeof(param_str));
} else {
snprintf(param_str, sizeof(param_str), "%d", i);
}
/* Run all the parameterized tests in the suite */
actual_test_count += trusty_unittest_run_test_suite(
param_entry->suite, true);
i++;
}
}
}
if (actual_test_count != expected_test_count) {
trusty_unittest_printf("[ RUN ] %s.test_count_match_check\n",
suite ? suite : "all_suites");
trusty_unittest_printf(
"[----------] %d tests ran, but expected %d tests.\n",
actual_test_count, expected_test_count);
trusty_unittest_print_status_name(suite ? suite : "all_suites",
"test_count_match_check", " FAILED ");
++_test_context.tests_failed;
++_test_context.tests_total;
} else if (actual_test_count == 0 && _test_context.tests_disabled == 0) {
trusty_unittest_printf("[ RUN ] %s.test_count_empty_check\n",
suite ? suite : "all_suites");
trusty_unittest_printf("[----------] 0 tests but none disabled.\n");
trusty_unittest_print_status_name(suite ? suite : "all_suites",
"test_count_empty_check", " FAILED ");
++_test_context.tests_failed;
++_test_context.tests_total;
}
trusty_unittest_printf(
"[==========] %d tests ran (%" PRIu64 " ms total).\n",
_test_context.tests_total, _test_context.suite_duration_ms);
if (_test_context.tests_total != _test_context.tests_failed) {
trusty_unittest_printf(
"[ PASSED ] %d tests.\n",
_test_context.tests_total - _test_context.tests_failed);
}
if (_test_context.tests_skipped) {
trusty_unittest_printf("[ SKIPPED ] %d tests.\n",
_test_context.tests_skipped);
}
if (_test_context.tests_disabled) {
trusty_unittest_printf("[ DISABLED ] %d tests.\n",
_test_context.tests_disabled);
}
if (_test_context.tests_failed) {
trusty_unittest_printf("[ FAILED ] %d tests.\n",
_test_context.tests_failed);
}
return _test_context.tests_failed == 0;
}
static inline bool RUN_ALL_TESTS(void) {
return RUN_ALL_SUITE_TESTS(NULL);
}
/**
* GTEST_SKIP() - Skip current test
*
* This will skip the current test without triggering a failure. It will use
* same test_abort label as the ASSERT_... macros. Calling this after a test has
* failed or calling ASSERT_.../EXPECT_... macros after GTEST_SKIP has jumped
* to test_abort is not supported.
*/
#define GTEST_SKIP() \
{ \
if (!_test_context.skipped) { \
_test_context.skipped = true; \
_test_context.tests_skipped++; \
} \
goto test_abort; \
}
#define ASSERT_EXPECT_TEST(op, op_pre, op_sep, op_args, is_hard_fail, \
fail_action, vals_type, vals_format_placeholder, \
print_cast, print_op, val1, val2, extra_msg...) \
{ \
vals_type _val1 = val1; \
vals_type _val2 = val2; \
if (!op_pre(_val1 DELETE_PAREN op_sep _val2 DELETE_PAREN op_args)) { \
trusty_unittest_printf("%s: @ %s:%d\n", _test_context.test_name, \
__FILE__, __LINE__); \
trusty_unittest_printf( \
" expected: %s (" vals_format_placeholder ") " print_op \
" %s (" vals_format_placeholder ")\n", \
#val1, print_cast _val1, #val2, print_cast _val2); \
trusty_unittest_printf(" " extra_msg); \
trusty_unittest_printf("\n"); \
if (_test_context.all_ok) { \
_test_context.all_ok = false; \
_test_context.tests_failed++; \
} \
_test_context.hard_fail |= is_hard_fail; \
fail_action \
} \
}
static inline bool HasFailure(void) {
return !_test_context.all_ok;
}
static inline bool HasFatalFailure(void) {
return _test_context.hard_fail;
}
/**
* INSTANTIATE_TEST_SUITE_P - Instantiate parameters for a test suite
* @inst_name: Name for instantiation of parameters. Should not contain
* underscores.
* @suite_name: Name of test suite associated with the parameters
* @param_gen: One of the parameter generators (see below)
* @param_to_string: Function of type &typedef test_param_to_string_t
* used to convert a parameter to its string form. This
* argument is optional.
*
* Parameter Generators:
* testing_Range(being, end, step):
* Returns the values {begin, being+step, being+step+step, ...} up to but not
* including end. step is optional and defaults to 1.
*
* testing_Values(v1, v2, ..., vN):
* Returns the values {v1, v2, ..., vN)
*
* testing_ValuesIn(array)
* Returns the values in array
*
* testing_Bool()
* Returns {false, true}
*
* testing_Combine(g1, [g2, g3, g4, g5]):
* Returns the values of the combinations of the provided generators
* (min 1, max 5) an as an array.
*/
#define INSTANTIATE_TEST_SUITE_P(inst_name, suite_name, param_gen_args...) \
INSTANTIATE_TEST_SUITE_P_INTERNAL(inst_name, suite_name, param_gen_args, \
NULL, )
/**
* GetParam() - Returns a pointer to the current test parameter
*
* Context: This function can be called within a parameterized test to
* retrieve the current parameter to the test.
*
* Return: a pointer to the current test parameter.
*
* This pointer should be cast to the expected parameter type for the executing
* test.
*/
static inline const void* GetParam(void) {
return _test_context.test_param;
}
#define ASSERT_EXPECT_LONG_TEST(op, is_hard_fail, fail_action, val1, val2, \
args...) \
ASSERT_EXPECT_TEST(op, , (op), (), is_hard_fail, fail_action, \
__typeof__(val2), "%ld", (long), #op, val1, val2, args)
#define ASSERT_EXPECT_STR_TEST(func, is_hard_fail, fail_action, args...) \
ASSERT_EXPECT_TEST(func, func, (, ), (), is_hard_fail, fail_action, \
const char*, "\"%s\"", , args)
#define ASSERT_EXPECT_STRN_TEST(func, n, is_hard_fail, fail_action, args...) \
ASSERT_EXPECT_TEST(func, func, (, ), (, n), is_hard_fail, fail_action, \
const char*, "\"%s\"", , args)
#define EXPECT_TEST(op, args...) ASSERT_EXPECT_LONG_TEST(op, false, , args)
#define EXPECT_EQ(args...) EXPECT_TEST(==, args)
#define EXPECT_NE(args...) EXPECT_TEST(!=, args)
#define EXPECT_LT(args...) EXPECT_TEST(<, args)
#define EXPECT_LE(args...) EXPECT_TEST(<=, args)
#define EXPECT_GT(args...) EXPECT_TEST(>, args)
#define EXPECT_GE(args...) EXPECT_TEST(>=, args)
#define EXPECT_STR_TEST(func, args...) \
ASSERT_EXPECT_STR_TEST(func, false, , args)
#define EXPECT_STREQ(args...) EXPECT_STR_TEST(!strcmp, "==", args)
#define EXPECT_STRNE(args...) EXPECT_STR_TEST(strcmp, "!=", args)
#define EXPECT_STRCASEEQ(args...) \
EXPECT_STR_TEST(!strcasecmp, "== (ignoring case)", args)
#define EXPECT_STRCASENE(args...) \
EXPECT_STR_TEST(strcasecmp, "!= (ignoring case)", args)
#define EXPECT_STRN_TEST(func, n, args...) \
ASSERT_EXPECT_STRN_TEST(func, n, false, , args)
#define EXPECT_STREQN(val1, val2, n, args...) \
EXPECT_STR_TEST(!strncmp, n, "==", val1, val2, args)
#define EXPECT_STRNEN(val1, val2, n, args...) \
EXPECT_STR_TEST(strncmp, n, "!=", val1, val2, args)
#define EXPECT_STRCASEEQN(val1, val2, n, args...) \
EXPECT_STR_TEST(!strncasecmp, n, "== (ignoring case)", val1, val2, args)
#define EXPECT_STRCASENEN(val1, val2, n, args...) \
EXPECT_STR_TEST(strncasecmp, n, "!= (ignoring case)", val1, val2, args)
#define ASSERT_TEST(op, args...) \
ASSERT_EXPECT_LONG_TEST(op, true, goto test_abort;, args)
#define ASSERT_EQ(args...) ASSERT_TEST(==, args)
#define ASSERT_NE(args...) ASSERT_TEST(!=, args)
#define ASSERT_LT(args...) ASSERT_TEST(<, args)
#define ASSERT_LE(args...) ASSERT_TEST(<=, args)
#define ASSERT_GT(args...) ASSERT_TEST(>, args)
#define ASSERT_GE(args...) ASSERT_TEST(>=, args)
#define ASSERT_STR_TEST(func, args...) \
ASSERT_EXPECT_STR_TEST(func, true, goto test_abort;, args)
#define ASSERT_STREQ(args...) ASSERT_STR_TEST(!strcmp, "==", args)
#define ASSERT_STRNE(args...) ASSERT_STR_TEST(strcmp, "!=", args)
#define ASSERT_STRCASEEQ(args...) \
ASSERT_STR_TEST(!strcasecmp, "== (ignoring case)", args)
#define ASSERT_STRCASENE(args...) \
ASSERT_STR_TEST(strcasecmp, "!= (ignoring case)", args)
#define ASSERT_STRN_TEST(func, n, args...) \
ASSERT_EXPECT_STRN_TEST(func, n, true, goto test_abort;, args)
#define ASSERT_STREQN(val1, val2, n, args...) \
ASSERT_STRN_TEST(!strncmp, n, "==", val1, val2, args)
#define ASSERT_STRNEN(val1, val2, n, args...) \
ASSERT_STRN_TEST(strncmp, n, "!=", val1, val2, args)
#define ASSERT_STRCASEEQN(val1, val2, n, args...) \
ASSERT_STRN_TEST(!strncasecmp, n, "== (ignoring case)", val1, val2, args)
#define ASSERT_STRCASENEN(val1, val2, n, args...) \
ASSERT_STRN_TEST(strncasecmp, n, "!= (ignoring case)", val1, val2, args)
__END_CDECLS