Cleanup CUnit integration and add support for theories

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
This commit is contained in:
Jeroen Koekkoek 2018-11-01 19:32:24 +01:00
parent 6e1df4c564
commit 630178fb12
20 changed files with 764 additions and 555 deletions

View file

@ -11,11 +11,195 @@
#
find_package(CUnit REQUIRED)
include(Glob)
set(CUNIT_DIR "${CMAKE_CURRENT_LIST_DIR}/CUnit")
function(add_cunit_executable target)
function(get_cunit_header_file SOURCE_FILE HEADER_FILE)
# Return a unique (but consistent) filename where Theory macros can be
# written. The path that will be returned is the location to a header file
# located in the same relative directory, using the basename of the source
# file postfixed with .h. e.g. <project>/foo/bar.h would be converted to
# <project>/build/foo/bar.h.
if(IS_ABSOLUTE "${SOURCE_FILE}")
file(RELATIVE_PATH SOURCE_FILE "${PROJECT_SOURCE_DIR}" "${SOURCE_FILE}")
endif()
get_filename_component(basename "${SOURCE_FILE}" NAME_WE)
get_filename_component(dir "${SOURCE_FILE}" DIRECTORY)
set(${HEADER_FILE} "${CMAKE_BINARY_DIR}/${dir}/${basename}.h" PARENT_SCOPE)
endfunction()
function(parse_cunit_fixtures INPUT TEST_DISABLED TEST_TIMEOUT)
if(INPUT MATCHES ".disabled${s}*=${s}*([tT][rR][uU][eE]|[0-9]+)")
set(${TEST_DISABLED} "TRUE" PARENT_SCOPE)
else()
set(${TEST_DISABLED} "FALSE" PARENT_SCOPE)
endif()
if(INPUT MATCHES ".timeout${s}*=${s}*([0-9]+)")
set(${TEST_TIMEOUT} "${CMAKE_MATCH_1}" PARENT_SCOPE)
else()
set(${TEST_TIMEOUT} "0" PARENT_SCOPE)
endif()
endfunction()
# Parse a single source file, generate a header file with theory definitions
# (if applicable) and return suite and test definitions.
function(process_cunit_source_file SOURCE_FILE HEADER_FILE SUITES TESTS)
set(x "\\*")
set(s "[ \t\r\n]")
set(s_or_x "[ \t\r\n\\*]")
set(w "[_a-zA-Z0-9]")
set(ident_expr "(${s}*${w}+${s}*)")
# Very basic type recognition, only things that contain word characters and
# pointers are handled. And since this script does not actually have to
# compile any code, type checking is left to the compiler. An error (or
# warning) will be thrown if something is off.
#
# The "type" regular expression below will match things like:
# - <word> <word>
# - <word> *<word>
# - <word>* <word> *<word>
set(type_expr "(${s}*${w}+${x}*${s}+${s_or_x}*)+")
set(param_expr "${type_expr}${ident_expr}")
# Test fixture support (based on test fixtures as implemented in Criterion),
# to enable per-test (de)initializers, which is very different from
# per-suite (de)initializers, and timeouts.
#
# The following fixtures are supported:
# - init
# - fini
# - disabled
# - timeout
set(data_expr "(${s}*,${s}*\\.${w}+${s}*=[^,]+)*")
set(suites_wo_init_n_clean)
set(suites_w_init)
set(suites_w_clean)
file(READ "${SOURCE_FILE}" content)
# CU_Init and CU_Clean
#
# Extract all suite initializers and deinitializers so that the list of
# suites can be probably populated when tests and theories are parsed. Suites
# are only registered if it contains at least one test or theory.
set(suite_expr "CU_(Init|Clean)${s}*\\(${ident_expr}\\)")
string(REGEX MATCHALL "${suite_expr}" matches "${content}")
foreach(match ${matches})
string(REGEX REPLACE "${suite_expr}" "\\2" suite "${match}")
if("${match}" MATCHES "CU_Init")
list(APPEND suites_w_init ${suite})
elseif("${match}" MATCHES "CU_Clean")
list(APPEND suites_w_deinit ${suite})
endif()
endforeach()
# CU_Test
set(test_expr "CU_Test${s}*\\(${ident_expr},${ident_expr}${data_expr}\\)")
string(REGEX MATCHALL "${test_expr}" matches "${content}")
foreach(match ${matches})
string(REGEX REPLACE "${test_expr}" "\\1" suite "${match}")
string(REGEX REPLACE "${test_expr}" "\\2" test "${match}")
# Remove leading and trailing whitespace
string(STRIP "${suite}" suite)
string(STRIP "${test}" test)
# Extract fixtures that must be handled by CMake (.disabled and .timeout).
parse_cunit_fixtures("${match}" disabled timeout)
list(APPEND suites_wo_init_n_clean "${suite}")
list(APPEND tests "${suite}:${test}:${disabled}:${timeout}")
endforeach()
# CU_Theory
#
# CU_Theory signatures must be recognized in order to generate structures to
# hold the CU_DataPoints declarations. The generated type is added to the
# compile definitions and inserted by the preprocessor when CU_TheoryDataPoints
# is expanded.
#
# NOTE: Since not all compilers support pushing function-style definitions
# from the command line (CMake will generate a warning too), a header
# file is generated instead. A define is pushed and expanded at
# compile time. It is included by CUnit/Theory.h.
get_cunit_header_file("${SOURCE_FILE}" header)
set(theory_expr "CU_Theory${s}*\\(${s}*\\((${param_expr}(,${param_expr})*)\\)${s}*,${ident_expr},${ident_expr}${data_expr}\\)")
string(REGEX MATCHALL "${theory_expr}" matches "${content}")
foreach(match ${matches})
if(NOT theories)
# Ensure generated header is truncated before anything is written.
file(WRITE "${header}" "")
endif()
string(REGEX REPLACE "${theory_expr}" "\\1" params "${match}")
string(REGEX REPLACE "${theory_expr}" "\\7" suite "${match}")
string(REGEX REPLACE "${theory_expr}" "\\8" test "${match}")
# Remove leading and trailing whitespace
string(STRIP "${params}" params)
string(STRIP "${suite}" suite)
string(STRIP "${test}" test)
# Convert parameters from a string to a list
string(REGEX REPLACE "${s}*,${s}*" ";" params "${params}")
# Extract fixtures that must be handled by CMake (.disabled and .timeout)
parse_cunit_fixtures("${match}" disabled timeout)
list(APPEND suites_wo_init_n_clean "${suite}")
list(APPEND theories "${suite}:${test}:${disabled}:${timeout}")
set(sep)
set(size "CU_TheoryDataPointsSize_${suite}_${test}(datapoints) (")
set(slice "CU_TheoryDataPointsSlice_${suite}_${test}(datapoints, index) (")
set(typedef "CU_TheoryDataPointsTypedef_${suite}_${test}() {")
foreach(param ${params})
string(
REGEX REPLACE "(${type_expr})${ident_expr}" "\\3" name "${param}")
string(
REGEX REPLACE "(${type_expr})${ident_expr}" "\\1" type "${param}")
string(STRIP "${name}" name)
string(STRIP "${type}" type)
set(slice "${slice}${sep} datapoints.${name}.p[index]")
if (NOT sep)
set(size "${size} datapoints.${name}.n")
set(sep ",")
endif()
set(typedef "${typedef} struct { size_t n; ${type} *p; } ${name};")
endforeach()
set(typedef "${typedef} }")
set(slice "${slice} )")
set(size "${size} )")
file(APPEND "${header}" "#define ${size}\n")
file(APPEND "${header}" "#define ${slice}\n")
file(APPEND "${header}" "#define ${typedef}\n")
endforeach()
# Propagate suites, tests and theories extracted from the source file.
list(REMOVE_DUPLICATES suites_wo_init_n_clean)
list(SORT suites_wo_init_n_clean)
foreach(suite ${suites_wo_init_n_clean})
set(init "FALSE")
set(clean "FALSE")
if(${suite} IN_LIST suites_w_init)
set(init "TRUE")
endif()
if(${suite} IN_LIST suites_w_deinit)
set(clean "TRUE")
endif()
list(APPEND suites "${suite}:${init}:${clean}")
endforeach()
if(theories)
set(${HEADER_FILE} "${header}" PARENT_SCOPE)
else()
unset(${HEADER_FILE} PARENT_SCOPE)
endif()
set(${SUITES} ${suites} PARENT_SCOPE)
set(${TESTS} ${tests};${theories} PARENT_SCOPE)
endfunction()
function(add_cunit_executable TARGET)
# Retrieve location of shared libary, which is need to extend the PATH
# environment variable on Microsoft Windows, so that the operating
# system can locate the .dll that it was linked against.
@ -24,129 +208,93 @@ function(add_cunit_executable target)
get_target_property(CUNIT_IMPORTED_LOCATION CUnit IMPORTED_LOCATION)
get_filename_component(CUNIT_LIBRARY_DIR "${CUNIT_IMPORTED_LOCATION}" PATH)
# Generate semi-random filename to store the generated code in to avoid
# possible naming conflicts.
string(RANDOM random)
set(runner "${target}_${random}")
set(decls)
set(defns)
set(sources)
set(s "[ \t\r\n]") # space
set(w "[0-9a-zA-Z_]") # word
set(param "${s}*(${w}+)${s}*")
set(pattern "CUnit_${w}+${s}*\\(${param}(,${param}(,${param})?)?\\)")
foreach(source ${ARGN})
if((EXISTS "${source}" OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${source}"))
unset(suites)
unset(tests)
glob(filenames "c" ${ARGN})
process_cunit_source_file("${source}" header suites tests)
if(header)
set_property(
SOURCE "${source}"
PROPERTY COMPILE_DEFINITIONS CU_THEORY_INCLUDE_FILE=\"${header}\")
endif()
foreach(filename ${filenames})
file(READ "${filename}" contents)
string(REGEX MATCHALL "${pattern}" captures "${contents}")
foreach(suite ${suites})
string(REPLACE ":" ";" suite ${suite})
list(GET suite 2 clean)
list(GET suite 1 init)
list(GET suite 0 suite)
set(init_func "NULL")
set(clean_func "NULL")
if(init)
set(decls "${decls}\nCU_InitDecl(${suite});")
set(init_func "CU_InitName(${suite})")
endif()
if(clean)
set(decls "${decls}\nCU_CleanDecl(${suite});")
set(clean_func "CU_CleanName(${suite})")
endif()
set(defns "${defns}\nADD_SUITE(${suite}, ${init_func}, ${clean_func});")
endforeach()
list(APPEND sources "${filename}")
list(LENGTH captures length)
if(length)
foreach(capture ${captures})
string(REGEX REPLACE "${pattern}" "\\1" suite "${capture}")
foreach(test ${tests})
string(REPLACE ":" ";" test ${test})
list(GET test 3 timeout)
list(GET test 2 disabled)
list(GET test 0 suite)
list(GET test 1 test)
if("${capture}" MATCHES "CUnit_Suite_Initialize")
list(APPEND suites ${suite})
list(APPEND suites_w_init ${suite})
elseif("${capture}" MATCHES "CUnit_Suite_Cleanup")
list(APPEND suites ${suite})
list(APPEND suites_w_deinit ${suite})
elseif("${capture}" MATCHES "CUnit_Test")
list(APPEND suites ${suite})
set(enable "true")
if(disabled)
set(enable "false")
endif()
if(NOT timeout)
set(timeout 10)
endif()
# Specifying a test name is mandatory
if("${capture}" MATCHES ",")
string(REGEX REPLACE "${pattern}" "\\3" test "${capture}")
else()
message(FATAL_ERROR "Bad CUnit_Test signature in ${filename}")
endif()
set(decls "${decls}\nCU_TestDecl(${suite}, ${test});")
set(defns "${defns}\nADD_TEST(${suite}, ${test}, ${enable});")
set(ctest "CUnit_${suite}_${test}")
# Specifying if a test is enabled is optional
set(enable "true")
if("${capture}" MATCHES ",${param},")
string(REGEX REPLACE "${pattern}" "\\5" enable "${capture}")
endif()
if((NOT "${enable}" STREQUAL "true") AND
(NOT "${enable}" STREQUAL "false"))
message(FATAL_ERROR "Bad CUnit_Test signature in ${filename}")
endif()
list(APPEND tests "${suite}:${test}:${enable}")
else()
message(FATAL_ERROR "Bad CUnit signature in ${filename}")
add_test(
NAME ${ctest}
COMMAND ${TARGET} -a -r "${suite}-${test}" -s ${suite} -t ${test})
set_property(TEST ${ctest} PROPERTY TIMEOUT ${timeout})
set_property(TEST ${ctest} PROPERTY DISABLED ${disabled})
if(APPLE)
set_property(
TEST ${ctest}
PROPERTIES ENVIRONMENT
"DYLD_LIBRARY_PATH=${CUNIT_LIBRARY_DIR}:$ENV{DYLD_LIBRARY_PATH}")
elseif(WIN32 AND ${CUNIT_LIBRARY_TYPE} STREQUAL "SHARED_LIBRARY")
set_property(
TEST ${ctest}
PROPERTY ENVIRONMENT
"PATH=${CUNIT_LIBRARY_DIR};$ENV{PATH}")
endif()
endforeach()
list(APPEND sources "${source}")
endif()
endforeach()
# Test suite signatures can be decided on only after everything is parsed.
set(lf "\n")
set(declf "")
set(deflf "")
list(REMOVE_DUPLICATES suites)
list(SORT suites)
foreach(suite ${suites})
set(init "NULL")
set(deinit "NULL")
if(${suite} IN_LIST suites_w_init)
set(init "CUnit_Suite_Initialize__(${suite})")
set(decls "${decls}${declf}CUnit_Suite_Initialize_Decl__(${suite});")
set(declf "${lf}")
endif()
if(${suite} IN_LIST suites_w_deinit)
set(deinit "CUnit_Suite_Cleanup__(${suite})")
set(decls "${decls}${declf}CUnit_Suite_Cleanup_Decl__(${suite});")
set(declf "${lf}")
endif()
set(defs "${defs}${deflf}CUnit_Suite__(${suite}, ${init}, ${deinit});")
set(deflf "${lf}")
endforeach()
list(REMOVE_DUPLICATES tests)
list(SORT tests)
foreach(entry ${tests})
string(REPLACE ":" ";" entry ${entry})
list(GET entry 0 suite)
list(GET entry 1 test)
list(GET entry 2 enable)
set(decls "${decls}${declf}CUnit_Test_Decl__(${suite}, ${test});")
set(declf "${lf}")
set(defs "${defs}${deflf}CUnit_Test__(${suite}, ${test}, ${enable});")
set(deflf "${lf}")
add_test(
NAME "CUnit_${suite}_${test}"
COMMAND ${target} -a -r "${suite}-${test}" -s ${suite} -t ${test})
set_tests_properties("CUnit_${suite}_${test}" PROPERTIES TIMEOUT 10)
if(APPLE)
set_property(
TEST "CUnit_${suite}_${test}"
PROPERTY ENVIRONMENT "DYLD_LIBRARY_PATH=${CUNIT_LIBRARY_DIR}:$ENV{DYLD_LIBRARY_PATH}")
endif()
if(WIN32 AND ${CUNIT_LIBRARY_TYPE} STREQUAL "SHARED_LIBRARY")
set_property(
TEST "CUnit_${suite}_${test}"
PROPERTY ENVIRONMENT "PATH=${CUNIT_LIBRARY_DIR};$ENV{PATH}")
endif()
endforeach()
set(root "${CUNIT_DIR}")
set(CUnit_Decls "${decls}")
set(CUnit_Defs "${defs}")
configure_file("${root}/src/main.c.in" "${runner}.c" @ONLY)
add_executable(${target} "${runner}.c" "${root}/src/runner.c" ${sources})
target_link_libraries(${target} CUnit)
target_include_directories(${target} PRIVATE "${root}/include")
configure_file(
"${CUNIT_DIR}/src/main.c.in" "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.c" @ONLY)
if("2.1.3" VERSION_LESS_EQUAL
"${CUNIT_VERSION_MAJOR}.${CUNIT_VERSION_MINOR}.${CUNIT_VERSION_PATCH}")
set_source_files_properties(
"${root}/src/runner.c" PROPERTIES COMPILE_DEFINITIONS HAVE_ENABLE_JUNIT_XML)
set_property(
SOURCE "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.c"
PROPERTY COMPILE_DEFINITIONS HAVE_ENABLE_JUNIT_XML)
endif()
add_executable(
${TARGET} "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.c" ${sources})
target_link_libraries(${TARGET} CUnit)
target_include_directories(${TARGET} PRIVATE "${CUNIT_DIR}/include")
endfunction()

View file

@ -1,83 +0,0 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef CUNIT_RUNNER_H
#define CUNIT_RUNNER_H
#include <stdbool.h>
#include <CUnit/CUnit.h>
#include <CUnit/CUError.h>
#if defined (__cplusplus)
extern "C" {
#endif
#define CUnit_Suite_Initialize_Name__(s) \
s ## _Initialize
#define CUnit_Suite_Initialize(s) \
int CUnit_Suite_Initialize_Name__(s)(void)
#define CUnit_Suite_Initialize_Decl__(s) \
extern CUnit_Suite_Initialize(s)
#define CUnit_Suite_Initialize__(s) \
CUnit_Suite_Initialize_Name__(s)
#define CUnit_Suite_Cleanup_Name__(s) \
s ## _Cleanup
#define CUnit_Suite_Cleanup(s) \
int CUnit_Suite_Cleanup_Name__(s)(void)
#define CUnit_Suite_Cleanup_Decl__(s) \
extern CUnit_Suite_Cleanup(s)
#define CUnit_Suite_Cleanup__(s) \
CUnit_Suite_Cleanup_Name__(s)
#define CUnit_Test_Name__(s, t) \
s ## _ ## t
#define CUnit_Test(s, t, ...) \
void CUnit_Test_Name__(s, t)(void)
#define CUnit_Test_Decl__(s, t) \
extern CUnit_Test(s, t)
#define CUnit_Suite__(s, c, d) \
cu_runner_add_suite(#s, c, d)
#define CUnit_Test__(s, t, e) \
cu_runner_add_test(#s, #t, CUnit_Test_Name__(s, t), e)
CU_ErrorCode
cu_runner_init(
int argc,
char *argv[]);
void
cu_runner_fini(
void);
void
cu_runner_add_suite(
const char *suite,
CU_InitializeFunc pInitFunc,
CU_CleanupFunc pCleanFunc);
void
cu_runner_add_test(
const char *suite,
const char *test,
CU_TestFunc pTestFunc,
bool enable);
CU_ErrorCode
cu_runner_run(
void);
#if defined (__cplusplus)
}
#endif
#endif /* CUNIT_RUNNER_H */

View file

@ -0,0 +1,71 @@
#ifndef CUNIT_TEST_H
#define CUNIT_TEST_H
#include <stdbool.h>
#include <CUnit/CUnit.h>
#include <CUnit/CUError.h>
#if defined (__cplusplus)
extern "C" {
#endif
typedef void(*cu_test_init_func_t)(void);
typedef void(*cu_test_fini_func_t)(void);
typedef struct {
cu_test_init_func_t init;
cu_test_fini_func_t fini;
int disabled; /* Parsed by CMake, used at test registration in main. */
int timeout; /* Parsed by CMake, used at test registration in CMake. */
} cu_test_data_t;
#define CU_InitName(suite) \
CU_Init_ ## suite
#define CU_CleanName(suite) \
CU_Fini_ ## suite
#define CU_TestName(suite, test) \
CU_Test_ ## suite ## _ ## test
#define CU_TestProxyName(suite, test) \
CU_TestProxy_ ## suite ## _ ## test
#define CU_Init(suite) \
int CU_InitName(suite)(void)
#define CU_InitDecl(suite) \
extern CU_Init(suite)
#define CU_Clean(suite) \
int CU_CleanName(suite)(void)
#define CU_CleanDecl(suite) \
extern CU_Clean(suite)
/* CU_Test generates a wrapper function that takes care of per-test
initialization and deinitialization, if provided in the CU_Test
signature. */
#define CU_Test(suite, test, ...) \
static void CU_TestName(suite, test)(void); \
\
void CU_TestProxyName(suite, test)(void) { \
static const cu_test_data_t data = { __VA_ARGS__ }; \
\
if (data.init != NULL) { \
data.init(); \
} \
\
CU_TestName(suite, test)(); \
\
if (data.fini != NULL) { \
data.fini(); \
} \
} \
\
static void CU_TestName(suite, test)(void)
#define CU_TestDecl(suite, test) \
extern void CU_TestProxyName(suite, test)(void)
#if defined (__cplusplus)
}
#endif
#endif /* CUNIT_TEST_H */

View file

@ -0,0 +1,72 @@
#ifndef CUNIT_THEORY_H
#define CUNIT_THEORY_H
/* Function-style macros cannot be defined on the command line. */
#ifdef CU_THEORY_INCLUDE_FILE
#include CU_THEORY_INCLUDE_FILE
#endif
#include "CUnit/Test.h"
#if defined (__cplusplus)
extern "C" {
#endif
#define CU_TheoryDataPointsName(suite, test) \
CU_TheoryDataPoints_ ## suite ## _ ## test
#define CU_TheoryDataPointsTypeName(suite, test) \
CU_TheoryDataPointsType_ ## suite ## _ ## test
#define CU_TheoryDataPointsSize(suite, test) \
CU_TheoryDataPointsSize_ ## suite ## _ ## test ( \
CU_TheoryDataPointsName(suite, test))
#define CU_TheoryDataPointsSlice(suite, test, index) \
CU_TheoryDataPointsSlice_ ## suite ## _ ## test ( \
CU_TheoryDataPointsName(suite, test), index)
#define CU_TheoryDataPointsTypedef(suite, test) \
CU_TheoryDataPointsTypedef_ ## suite ## _ ## test()
#define CU_TheoryDataPoints(suite, test) \
struct CU_TheoryDataPointsTypeName(suite, test) \
CU_TheoryDataPointsTypedef(suite, test) ; \
\
static struct CU_TheoryDataPointsTypeName(suite, test) \
CU_TheoryDataPointsName(suite, test)
#define CU_DataPoints(type, ...) { \
.p = (type[]) { __VA_ARGS__ }, \
.n = (sizeof((type[]) { __VA_ARGS__ }) / sizeof(type)) \
}
#define CU_Theory(signature, suite, test, ...) \
static void CU_TestName(suite, test) signature; \
\
void CU_TestProxyName(suite, test)(void) { \
static const cu_test_data_t data = { __VA_ARGS__ }; \
size_t i, n; \
\
if (data.init != NULL) { \
data.init(); \
} \
\
for (i = 0, n = CU_TheoryDataPointsSize(suite, test); i < n; i++) { \
CU_TestName(suite, test) CU_TheoryDataPointsSlice(suite, test, i) ; \
} \
\
if (data.fini != NULL) { \
data.fini(); \
} \
} \
\
static void CU_TestName(suite, test) signature
#if defined (__cplusplus)
}
#endif
#endif /* CUNIT_THEORY_H */

View file

@ -9,23 +9,224 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Runner.h"
#include <stdio.h>
#include <string.h>
@CUnit_Decls@
#include <CUnit/Basic.h>
#include <CUnit/Automated.h>
#include <CUnit/Test.h>
int main (int argc, char *argv[])
static struct {
bool print_help;
bool automated;
bool junit;
const char *results;
CU_BasicRunMode mode;
CU_ErrorAction error_action;
const char *suite;
const char *test;
} opts = {
false,
false,
false,
NULL,
CU_BRM_NORMAL,
CUEA_IGNORE,
"*",
"*"
};
int patmatch(const char *pat, const char *str)
{
while (*pat) {
if (*pat == '?') {
/* any character will do */
if (*str++ == 0) {
return 0;
}
pat++;
} else if (*pat == '*') {
/* collapse a sequence of wildcards, requiring as many
characters in str as there are ?s in the sequence */
while (*pat == '*' || *pat == '?') {
if (*pat == '?' && *str++ == 0) {
return 0;
}
pat++;
}
/* try matching on all positions where str matches pat */
while (*str) {
if (*str == *pat && patmatch(pat+1, str+1)) {
return 1;
}
str++;
}
return *pat == 0;
} else {
/* only an exact match */
if (*str++ != *pat++) {
return 0;
}
}
}
return *str == 0;
}
static void usage(const char *name)
{
fprintf(stderr, "Usage: %s OPTIONS\n", name);
fprintf(stderr, "Try '%s -h' for more information\n", name);
}
static void help(const char *name)
{
printf("Usage: %s [OPTIONS]\n", name);
printf("\n");
printf("Possible options:\n");
printf(" -a run in automated mode\n");
printf(" -f fail fast\n");
printf(" -h display this help and exit\n");
printf(" -j junit format results \n");
printf(" -r FILENAME results file for automated run\n");
printf(" -s PATTERN run only tests in suites matching pattern\n");
printf(" -t PATTERN run only test matching pattern\n");
}
static CU_ErrorCode parse_options(int argc, char *argv[])
{
CU_ErrorCode err = CUE_SUCCESS;
for (int i = 1; err == CUE_SUCCESS && i < argc; i++) {
switch ((argv[i][0] == '-') ? argv[i][1] : 0) {
case 'a':
opts.automated = true;
break;
case 'f':
opts.error_action = CUEA_FAIL;
break;
case 'h':
opts.print_help = true;
break;
case 'j':
opts.junit = true;
break;
case 'r':
if((i+1) < argc){
opts.results = argv[++i];
break;
}
/* FALLS THROUGH */
case 's':
if ((i+1) < argc) {
opts.suite = argv[++i];
break;
}
/* FALLS THROUGH */
case 't':
if ((i+1) < argc) {
opts.test = argv[++i];
break;
}
/* FALLS THROUGH */
default:
err = (CU_ErrorCode)256;
CU_set_error(err); /* Will print as "Undefined Errpr" */
break;
}
}
return err;
}
void
add_suite(
const char *suite,
CU_InitializeFunc pInitFunc,
CU_CleanupFunc pCleanFunc)
{
CU_pSuite pSuite;
pSuite = CU_get_suite(suite);
if (pSuite == NULL) {
pSuite = CU_add_suite(suite, pInitFunc, pCleanFunc);
CU_set_suite_active(pSuite, patmatch(opts.suite, suite));
}
}
#define ADD_SUITE(suite, init, clean) \
add_suite(#suite, init, clean)
void
add_test(
const char *suite,
const char *test,
CU_TestFunc pTestFunc,
bool enable)
{
CU_pSuite pSuite;
CU_pTest pTest;
pSuite = CU_get_suite(suite);
pTest = CU_add_test(pSuite, test, pTestFunc);
CU_set_test_active(pTest, enable && patmatch(opts.test, test));
}
#define ADD_TEST(suite, test, enable) \
add_test(#suite, #test, CU_TestProxyName(suite, test), enable)
/* CMake will expand the macro below to declare generated functions. */
@decls@
int main(int argc, char *argv[])
{
CU_ErrorCode err;
if ((err = cu_runner_init(argc, argv))) {
goto err_init;
if ((err = parse_options(argc, argv)) != CUE_SUCCESS) {
usage(argv[0]);
return err;
} else if (opts.print_help) {
help(argv[0]);
return CUE_SUCCESS;
}
@CUnit_Defs@
if ((err = CU_initialize_registry()) != CUE_SUCCESS) {
fprintf(stderr, "CU_initialize_registry: %s\n", CU_get_error_msg());
return err;
}
err = cu_runner_run();
cu_runner_fini();
err_init:
return (int)err;
/* CMake will expand the macro below to register all suites and tests. */
@defns@
CU_set_error_action(opts.error_action);
if (opts.automated) {
if (opts.results != NULL) {
CU_set_output_filename(opts.results);
}
#if defined(HAVE_ENABLE_JUNIT_XML)
if (opts.junit) {
CU_automated_enable_junit_xml(CU_TRUE);
} else
#endif
{
CU_list_tests_to_file();
}
CU_automated_run_tests();
} else {
CU_basic_set_mode(opts.mode);
CU_basic_run_tests();
}
err = CU_get_error();
if (err == CUE_SUCCESS) {
err = (CU_ErrorCode)(CU_get_number_of_failures() == 0 ? 0 : 256);
}
CU_cleanup_registry();
return err;
}

View file

@ -1,215 +0,0 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <CUnit/Basic.h>
#include <CUnit/Automated.h>
#include "CUnit/Runner.h"
static struct cunit_runner {
bool automated;
bool junit;
const char * results;
CU_BasicRunMode mode;
CU_ErrorAction error_action;
const char *suite;
const char *test;
} runner;
static void
usage(
const char * name)
{
fprintf(stderr, "usage: %s [flags]\n", name);
fprintf(stderr, "Supported flags:\n");
fprintf(stderr, " -a run in automated mode\n");
fprintf(stderr, " -r <file_name> results file for automated run\n");
fprintf(stderr, " -j junit format results \n");
fprintf(stderr, " -f fail fast \n");
fprintf(stderr, " -s suite\n");
fprintf(stderr, " -t test\n");
}
int
patmatch(
const char *pat,
const char *str)
{
while (*pat) {
if (*pat == '?') {
/* any character will do */
if (*str++ == 0) {
return 0;
}
pat++;
} else if (*pat == '*') {
/* collapse a sequence of wildcards, requiring as many
characters in str as there are ?s in the sequence */
while (*pat == '*' || *pat == '?') {
if (*pat == '?' && *str++ == 0) {
return 0;
}
pat++;
}
/* try matching on all positions where str matches pat */
while (*str) {
if (*str == *pat && patmatch(pat+1, str+1)) {
return 1;
}
str++;
}
return *pat == 0;
} else {
/* only an exact match */
if (*str++ != *pat++) {
return 0;
}
}
}
return *str == 0;
}
CU_ErrorCode
cu_runner_init(
int argc,
char* argv[])
{
int c, i;
CU_ErrorCode e = CUE_SUCCESS;
runner.automated = false;
runner.junit = false;
runner.results = NULL;
runner.mode = CU_BRM_NORMAL;
runner.error_action = CUEA_IGNORE;
runner.suite = "*";
runner.test = "*";
for (i = 1; e == CUE_SUCCESS && i < argc; i++) {
c = (argv[i][0] == '-') ? argv[i][1] : -1;
switch (c) {
case 'a':
runner.automated = true;
break;
case 'f':
runner.error_action = CUEA_FAIL;
break;
case 'j':
runner.junit = true;
break;
case 'r':
if((i+1) < argc){
runner.results = argv[++i];
break;
}
/* FALLS THROUGH */
case 's':
if ((i+1) < argc) {
runner.suite = argv[++i];
break;
}
/* FALLS THROUGH */
case 't':
if ((i+1) < argc) {
runner.test = argv[++i];
break;
}
/* FALLS THROUGH */
default:
e = (CU_ErrorCode)256;
CU_set_error(e); /* Will print as "Undefined Errpr" */
usage(argv[0]);
break;
}
}
if (e == CUE_SUCCESS) {
if ((e = CU_initialize_registry()) != CUE_SUCCESS) {
fprintf(
stderr, "Test registry initialization failed: %s\n", CU_get_error_msg());
}
}
CU_set_error_action (runner.error_action);
return e;
}
void
cu_runner_fini(
void)
{
CU_cleanup_registry();
}
void
cu_runner_add_suite(
const char *suite,
CU_InitializeFunc pInitFunc,
CU_CleanupFunc pCleanFunc)
{
CU_pSuite pSuite;
pSuite = CU_get_suite(suite);
if (pSuite == NULL) {
pSuite = CU_add_suite(suite, pInitFunc, pCleanFunc);
//assert(pSuite != NULL);
CU_set_suite_active(pSuite, patmatch(runner.suite, suite));
}
}
void
cu_runner_add_test(
const char *suite,
const char *test,
CU_TestFunc pTestFunc,
bool enable)
{
CU_pSuite pSuite;
CU_pTest pTest;
pSuite = CU_get_suite(suite);
//assert(pSuite != NULL);
pTest = CU_add_test(pSuite, test, pTestFunc);
//assert(pTest != NULL);
CU_set_test_active(pTest, enable && patmatch(runner.test, test));
}
CU_ErrorCode
cu_runner_run(
void)
{
if (runner.automated) {
/* Generate CUnit or JUnit format results */
if (runner.results != NULL) {
CU_set_output_filename(runner.results);
}
if (runner.junit) {
#if defined(HAVE_ENABLE_JUNIT_XML)
CU_automated_enable_junit_xml(CU_TRUE);
#endif
} else {
CU_list_tests_to_file();
}
CU_automated_run_tests();
} else {
CU_basic_set_mode(runner.mode);
CU_basic_run_tests();
}
if (CU_get_error() == 0) {
return (CU_get_number_of_failures() != 0);
}
return CU_get_error();
}