cyclonedds/cmake/Modules/CUnit.cmake

312 lines
11 KiB
CMake
Raw Normal View History

2018-04-10 17:03:59 +02:00
#
# 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
#
find_package(CUnit REQUIRED)
set(CUNIT_DIR "${CMAKE_CURRENT_LIST_DIR}/CUnit")
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.
get_filename_component(SOURCE_FILE "${SOURCE_FILE}" ABSOLUTE)
file(RELATIVE_PATH SOURCE_FILE "${PROJECT_SOURCE_DIR}" "${SOURCE_FILE}")
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.
if(suites_wo_init_n_clean)
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()
endif()
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.
# On macOS, this mechanism is used to set the DYLD_LIBRARY_PATH.
get_target_property(CUNIT_LIBRARY_TYPE CUnit TYPE)
get_target_property(CUNIT_IMPORTED_LOCATION CUnit IMPORTED_LOCATION)
get_filename_component(CUNIT_LIBRARY_DIR "${CUNIT_IMPORTED_LOCATION}" PATH)
set(decls)
set(defns)
set(sources)
foreach(source ${ARGN})
if((EXISTS "${source}" OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${source}"))
unset(suites)
unset(tests)
process_cunit_source_file("${source}" header suites tests)
if(header)
set_property(
SOURCE "${source}"
PROPERTY COMPILE_DEFINITIONS CU_THEORY_INCLUDE_FILE=\"${header}\")
endif()
# Disable missing-field-initializers warnings as not having to specify
# every member, aka fixture, is intended behavior.
if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR
${CMAKE_C_COMPILER_ID} STREQUAL "AppleClang" OR
${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
set_property(
SOURCE "${source}"
PROPERTY COMPILE_FLAGS -Wno-missing-field-initializers)
endif()
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})")
2018-04-10 17:03:59 +02:00
endif()
set(defns "${defns}\nADD_SUITE(${suite}, ${init_func}, ${clean_func});")
2018-04-10 17:03:59 +02:00
endforeach()
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)
2018-04-10 17:03:59 +02:00
set(enable "true")
if(disabled)
set(enable "false")
endif()
if(NOT timeout)
set(timeout 10)
endif()
2018-04-10 17:03:59 +02:00
set(decls "${decls}\nCU_TestDecl(${suite}, ${test});")
set(defns "${defns}\nADD_TEST(${suite}, ${test}, ${enable});")
set(ctest "CUnit_${suite}_${test}")
2018-04-10 17:03:59 +02:00
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}
PROPERTY 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()
2018-04-10 17:03:59 +02:00
endforeach()
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_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})
Rearrange and fixup abstraction layer - Replace os_result by dds_retcode_t and move DDS return code defines down. Eliminates the need to convert between different return code types. - Move dds_time_t down and remove os_time. Eliminates the need to convert between different time representations and reduces code duplication. - Remove use of Microsoft source-code annotation language (SAL). SAL annotations are Microsoft specific and not very well documented. This makes it very difficult for contributers to write. - Rearrange the abstraction layer to be feature-based. The previous layout falsely assumed that the operating system dictates which implementation is best suited. For general purpose operating systems this is mostly true, but embedded targets require a slightly different approach and may not even offer all features. The new layout makes it possible to mix-and-match feature implementations and allows for features to not be implemented at all. - Replace the os prefix by ddsrt to avoid name collisions. - Remove various portions of unused and unwanted code. - Export thread names on all supported platforms. - Return native thread identifier on POSIX compatible platforms. - Add timed wait for condition variables that takes an absolute time. - Remove system abstraction for errno. The os_getErrno and os_setErrno were incorrect. Functions that might fail now simply return a DDS return code instead. - Remove thread-specific memory abstraction. os_threadMemGet and accompanying functions were a mess and their use has been eliminated by other changes in this commit. - Replace attribute (re)defines by ddsrt_ prefixed equivalents to avoid name collisions and problems with faulty __nonnull__ attributes. Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
2019-01-18 14:10:19 +01:00
target_link_libraries(${TARGET} PRIVATE CUnit)
target_include_directories(${TARGET} PRIVATE "${CUNIT_DIR}/include")
2018-04-10 17:03:59 +02:00
endfunction()