Skip to content

Commit

Permalink
#45: Rewrote cmake testing magic
Browse files Browse the repository at this point in the history
  • Loading branch information
aul12 committed Jan 1, 2023
1 parent 88e02a4 commit cec3c38
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 187 deletions.
170 changes: 94 additions & 76 deletions Tests/LowLevel/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,77 +1,95 @@
add_subdirectory(Mock)

declare_mock(${CMAKE_SOURCE_DIR}/Src/HAL/uart.h)

make_test(Drivers/bno055_uart)
target_link_libraries(Test_Drivers_bno055_uart PRIVATE Mock_HAL_uart)

make_test(Drivers/bno055)
target_link_libraries(Test_Drivers_bno055 PRIVATE Mock_Drivers_bno055_uart)

make_test(Drivers/ppm)
target_link_libraries(Test_Drivers_ppm PRIVATE Mock_HAL_pwm16bit)
target_link_libraries(Test_Drivers_ppm PRIVATE Mock_avr_io)

make_test(Drivers/protobuf)
target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_HAL_uart)
target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_Messages_MessageDecoding)
target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_Messages_MessageEncoding)
target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_Drivers_ring_buffer)

make_test(Drivers/ring_buffer)

make_test(Drivers/sbus)
target_link_libraries(Test_Drivers_sbus PRIVATE Mock_HAL_uart)
target_link_libraries(Test_Drivers_sbus PRIVATE Mock_Drivers_ring_buffer)

make_test(Components/imu)
target_link_libraries(Test_Components_imu PRIVATE Mock_Drivers_bno055)
target_link_libraries(Test_Components_imu PRIVATE Mock_util_delay)
target_link_libraries(Test_Components_imu PRIVATE Mock_Application_error_handler)

make_test(Components/remote)
target_link_libraries(Test_Components_remote PRIVATE Mock_Drivers_sbus)

make_test(Components/flightcomputer)
target_link_libraries(Test_Components_flightcomputer PRIVATE Mock_Drivers_protobuf)

make_test(Components/actuators)
target_link_libraries(Test_Components_actuators PRIVATE Mock_Drivers_ppm)

make_test(Components/system)
target_link_libraries(Test_Components_system PRIVATE Mock_avr_io)
target_link_libraries(Test_Components_system PRIVATE Mock_avr_wdt)
target_link_libraries(Test_Components_system PRIVATE Mock_avr_interrupt)
target_link_libraries(Test_Components_system PRIVATE Mock_HAL_timer8bit)
target_link_libraries(Test_Components_system PRIVATE Mock_Application_error_handler)

make_test(Application/controller)

make_test(Application/error_handler)
target_link_libraries(Test_Application_error_handler PRIVATE Mock_avr_io)
target_link_libraries(Test_Application_error_handler PRIVATE Mock_avr_wdt)

make_test(Application/mode_handler)
target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Application_error_handler)
target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Components_imu)
target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Components_remote)
target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Components_flightcomputer)


add_custom_target(RunAllTests DEPENDS ${AllTests})

add_custom_target(coverage.info
COMMAND lcov --capture --directory ${CMAKE_CURRENT_BINARY_DIR} --output-file ${CMAKE_CURRENT_BINARY_DIR}/coverage.info
DEPENDS ${AllTests})

add_custom_target(Coverage
COMMAND genhtml ${CMAKE_CURRENT_BINARY_DIR}/coverage.info --output-directory ${CMAKE_CURRENT_BINARY_DIR}/coverage
DEPENDS coverage.info)

add_custom_target(report.xml
COMMAND junit2html . --merge report.xml
DEPENDS ${AllTests})

add_custom_target(LLReport
COMMAND junit2html report.xml --report-matrix LLReport.html
DEPENDS report.xml)
function(make_fc_test)
cmake_parse_arguments(MAKE_FC_TEST
"" # Options
"MODULE" # One-Value Args
"DEPS" # Multi-Value Args
${ARGN})

set(headers)
foreach (module ${MAKE_FC_TEST_DEPS})
set(LOCAL_HEADER ${CMAKE_SOURCE_DIR}/Src/${module}.h)
set(SYSTEM_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/Mock/System/${module}.h)
if (EXISTS ${LOCAL_HEADER})
list(APPEND headers ${LOCAL_HEADER})
elseif (EXISTS ${SYSTEM_HEADER})
list(APPEND headers ${SYSTEM_HEADER})
else ()
message(FATAL_ERROR "Can't find ${module} for mocking (searched for ${LOCAL_HEADER} ${SYSTEM_HEADER})")
endif ()
endforeach ()

make_test(MODULE_UNDER_TEST ${CMAKE_SOURCE_DIR}/Src/${MAKE_FC_TEST_MODULE}.c
TEST_DEFINITION ${CMAKE_CURRENT_SOURCE_DIR}/${MAKE_FC_TEST_MODULE}.cpp
REQUIRED_HEADERS ${headers})
endfunction()

make_fc_test(MODULE Drivers/bno055_uart DEPS HAL/uart)
make_fc_test(MODULE Drivers/bno055 DEPS Drivers/bno055_uart)
make_fc_test(MODULE Drivers/ppm DEPS HAL/pwm16bit avr/io)
make_fc_test(MODULE Drivers/protobuf DEPS HAL/uart)


#make_test(Drivers/protobuf)
#target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_HAL_uart)
#target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_Messages_MessageDecoding)
#target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_Messages_MessageEncoding)
#target_link_libraries(Test_Drivers_protobuf PRIVATE Mock_Drivers_ring_buffer)
#
#make_test(Drivers/ring_buffer)
#
#make_test(Drivers/sbus)
#target_link_libraries(Test_Drivers_sbus PRIVATE Mock_HAL_uart)
#target_link_libraries(Test_Drivers_sbus PRIVATE Mock_Drivers_ring_buffer)
#
#make_test(Components/imu)
#target_link_libraries(Test_Components_imu PRIVATE Mock_Drivers_bno055)
#target_link_libraries(Test_Components_imu PRIVATE Mock_util_delay)
#target_link_libraries(Test_Components_imu PRIVATE Mock_Application_error_handler)
#
#make_test(Components/remote)
#target_link_libraries(Test_Components_remote PRIVATE Mock_Drivers_sbus)
#
#make_test(Components/flightcomputer)
#target_link_libraries(Test_Components_flightcomputer PRIVATE Mock_Drivers_protobuf)
#
#make_test(Components/actuators)
#target_link_libraries(Test_Components_actuators PRIVATE Mock_Drivers_ppm)
#
#make_test(Components/system)
#target_link_libraries(Test_Components_system PRIVATE Mock_avr_io)
#target_link_libraries(Test_Components_system PRIVATE Mock_avr_wdt)
#target_link_libraries(Test_Components_system PRIVATE Mock_avr_interrupt)
#target_link_libraries(Test_Components_system PRIVATE Mock_HAL_timer8bit)
#target_link_libraries(Test_Components_system PRIVATE Mock_Application_error_handler)
#
#make_test(Application/controller)
#
#make_test(Application/error_handler)
#target_link_libraries(Test_Application_error_handler PRIVATE Mock_avr_io)
#target_link_libraries(Test_Application_error_handler PRIVATE Mock_avr_wdt)
#
#make_test(Application/mode_handler)
#target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Application_error_handler)
#target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Components_imu)
#target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Components_remote)
#target_link_libraries(Test_Application_mode_handler PRIVATE Mock_Components_flightcomputer)
#
#
#add_custom_target(RunAllTests DEPENDS ${AllTests})
#
#add_custom_target(coverage.info
# COMMAND lcov --capture --directory ${CMAKE_CURRENT_BINARY_DIR} --output-file ${CMAKE_CURRENT_BINARY_DIR}/coverage.info
# DEPENDS ${AllTests})
#
#add_custom_target(Coverage
# COMMAND genhtml ${CMAKE_CURRENT_BINARY_DIR}/coverage.info --output-directory ${CMAKE_CURRENT_BINARY_DIR}/coverage
# DEPENDS coverage.info)
#
#add_custom_target(report.xml
# COMMAND junit2html . --merge report.xml
# DEPENDS ${AllTests})
#
#add_custom_target(LLReport
# COMMAND junit2html report.xml --report-matrix LLReport.html
# DEPENDS report.xml)
2 changes: 1 addition & 1 deletion Tests/LowLevel/Drivers/bno055_uart.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <Mock/HAL/uart.hpp>
#include <Mock/uart.hpp>
#include <gtest/gtest.h>

extern "C" {
Expand Down
158 changes: 48 additions & 110 deletions Tests/LowLevel/Mock/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,143 +10,81 @@ FetchContent_MakeAvailable(gtest)
# Load mocking lib
add_subdirectory(Lib)

set(MockedModules
Drivers/bno055
Drivers/bno055_uart
Drivers/ppm
Drivers/protobuf
Drivers/ring_buffer
Drivers/sbus
HAL/adc
HAL/i2c
HAL/pwm16bit
HAL/spi
HAL/timer8bit
HAL/uart
Messages/MessageEncoding
Messages/MessageDecoding
Components/actuators
Components/flightcomputer
Components/imu
Components/remote
Components/system
Application/controller
Application/error_handler
Application/mode_handler)

set(MockedSystemModules
util/delay
avr/interrupt
avr/io
avr/wdt)

function(declare_mock mocked_module_header)

function(declare_mock mocked_module_header mock_lib_out)
# Build names/paths
get_filename_component(module_name ${mocked_module_header} NAME_WE)
set(mock_path ${CMAKE_CURRENT_BINARY_DIR}/Mock/Mock)
set(mock_cpp ${mock_path}/${module_name}.cpp)
set(mock_hpp ${mock_path}/${module_name}.hpp)
set(mock_lib ${module_name}.mock)

# Add a target which will autogenerate the mock source files
add_custom_command(
COMMAND python3 ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Lib/generate_mock.py ${mocked_module_header} ${mock_path}
DEPENDS ${mocked_module_header} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Lib/generate_mock.py
OUTPUT ${mock_cpp} ${mock_hpp})

# Add a library for the mocked module
add_library(${mock_lib} STATIC ${mock_cpp} ${mock_hpp})
target_link_libraries(${mock_lib} PUBLIC MockLib)
target_include_directories(${mock_lib} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/Mock)
# Set out name
set(${mock_lib_out} ${mock_lib} PARENT_SCOPE)

# Only create lib if not already exists
if (NOT TARGET ${mock_lib})
# Add a target which will autogenerate the mock source files
add_custom_command(
COMMAND python3 ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Lib/generate_mock.py ${mocked_module_header} ${mock_path}
DEPENDS ${mocked_module_header} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Lib/generate_mock.py
OUTPUT ${mock_cpp} ${mock_hpp})

# Add a library for the mocked module
add_library(${mock_lib} STATIC ${mock_cpp} ${mock_hpp})
target_link_libraries(${mock_lib} PUBLIC MockLib)
target_include_directories(${mock_lib} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/Mock)
endif ()
endfunction()

# Build mock sources and target for module mocks
foreach (MockedModule ${MockedModules})
# For the name generation replace all / in the path with _
string(REPLACE "/" "_" MockedModuleName ${MockedModule})
set(MockLibTarget Mock_${MockedModuleName})
set(MockPath ${CMAKE_CURRENT_BINARY_DIR}/Mock/Mock)
set(MockCpp ${MockPath}/${MockedModule}.cpp)
set(MockHpp ${MockPath}/${MockedModule}.hpp)
#target_link_libraries(Mock_Messages_MessageEncoding PUBLIC ToolboxPlaneMessageDefs)
#target_link_libraries(Mock_Messages_MessageDecoding PUBLIC ToolboxPlaneMessageDefs)
#target_link_libraries(Mock_Drivers_protobuf PUBLIC ToolboxPlaneMessageDefs)

# Add a target which will autogenerate the mock source files
add_custom_command(
COMMAND python3 ${CMAKE_SOURCE_DIR}/Tests/LowLevel/Mock/Lib/generate_mock.py ${CMAKE_SOURCE_DIR}/Src/${MockedModule}.h ${MockedModule} ${MockPath}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS
${CMAKE_SOURCE_DIR}/Src/${MockedModule}.h
${CMAKE_SOURCE_DIR}/Src/${MockedModule}.c
Lib/generate_mock.py
OUTPUT ${MockCpp} ${MockHpp})

# Add a library for the mocked module
add_library(${MockLibTarget} STATIC ${MockCpp} ${MockHpp})
target_link_libraries(${MockLibTarget} PUBLIC MockLib)
target_include_directories(${MockLibTarget} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/Mock)
endforeach ()

target_link_libraries(Mock_Messages_MessageEncoding PUBLIC ToolboxPlaneMessageDefs)
target_link_libraries(Mock_Messages_MessageDecoding PUBLIC ToolboxPlaneMessageDefs)
target_link_libraries(Mock_Drivers_protobuf PUBLIC ToolboxPlaneMessageDefs)

# Build mock sources and target for system mocks
foreach (MockedModule ${MockedSystemModules})
# For the name generation replace all / in the path with _
string(REPLACE "/" "_" MockedModuleName ${MockedModule})
set(MockLibTarget Mock_${MockedModuleName})
set(MockPath ${CMAKE_CURRENT_BINARY_DIR}/Mock/Mock)
set(MockCpp ${MockPath}/${MockedModule}.cpp)
set(MockHpp ${MockPath}/${MockedModule}.hpp)

# Add a target which will autogenerate the mock source files
add_custom_command(
COMMAND python3 ${CMAKE_SOURCE_DIR}/Tests/LowLevel/Mock/Lib/generate_mock.py ${CMAKE_SOURCE_DIR}/Tests/LowLevel/Mock/System/${MockedModule}.h ${MockedModule} ${MockPath}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS
${CMAKE_SOURCE_DIR}/Tests/LowLevel/Mock/System/${MockedModule}.h
Lib/generate_mock.py
OUTPUT ${MockCpp} ${MockHpp})

# Add a library for the mocked module
add_library(${MockLibTarget} STATIC ${MockCpp} ${MockHpp})
target_link_libraries(${MockLibTarget} PUBLIC MockLib)
target_include_directories(${MockLibTarget} PUBLIC ${CMAKE_SOURCE_DIR}/Tests/LowLevel/Mock/System)
target_include_directories(${MockLibTarget} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/Mock)
endforeach ()

set(AllTests)

set(AllTestResults)

# Function to build a mock test for a module
function(make_test file_under_test)
string(REPLACE "/" "_" TestSuite ${file_under_test})
set(TestExecutable Test_${TestSuite})
function(make_test)
cmake_parse_arguments(MAKE_TEST
"" # Options
"MODULE_UNDER_TEST;TEST_DEFINITION" # One-Value Args
"REQUIRED_HEADERS" # Multi-Value Args
${ARGN})

get_filename_component(TestSuite ${MAKE_TEST_MODULE_UNDER_TEST} NAME_WE)
set(TestExecutable ${TestSuite}.test)

# Add a executable consisting of the function .c file and the test .cpp file
add_executable(${TestExecutable}
main.cpp
${CMAKE_SOURCE_DIR}/Src/${file_under_test}.c
${file_under_test}.cpp)

# Link against GTest libraries
target_link_libraries(${TestExecutable} PRIVATE gtest gmock pthread)
${MAKE_TEST_MODULE_UNDER_TEST}
${MAKE_TEST_TEST_DEFINITION})

# Enable coverage tracking
target_compile_options(${TestExecutable} PRIVATE --coverage -fprofile-arcs -ftest-coverage)
target_link_options(${TestExecutable} PRIVATE --coverage -fprofile-arcs -ftest-coverage)

# Set the macro TEST_NAME to the name of the tested module
string(REPLACE "/" "_" test_name ${file_under_test})
string(REPLACE "." "_" compiler_version ${CMAKE_C_COMPILER_VERSION})
set(test_name "${CMAKE_C_COMPILER_ID}_${compiler_version}_${CMAKE_BUILD_TYPE}_${test_name}")
set(test_name "${CMAKE_C_COMPILER_ID}_${compiler_version}_${CMAKE_BUILD_TYPE}_${TestSuite}")
target_compile_definitions(${TestExecutable} PRIVATE -DTEST_NAME=${test_name})

# Add target to run test
set(RunTargetName ${TestExecutable}_Run)
add_custom_target(${RunTargetName}
# Link against GTest libraries
target_link_libraries(${TestExecutable} PRIVATE gtest gmock pthread)

# Generate mocked libraries and link against them
foreach (REQUIRED_HEADER ${MAKE_TEST_REQUIRED_HEADERS})
declare_mock(${REQUIRED_HEADER} mock_name)
target_link_libraries(${TestExecutable} PRIVATE ${mock_name})
endforeach ()

# Create a target to run the test to be used as a dependency
add_custom_command(
OUTPUT ${test_name}.xml
COMMAND ${TestExecutable} --gtest_repeat=10 --gtest_shuffle --gtest_output=xml:${test_name}.xml
DEPENDS ${TestExecutable})

# Add test to list of tests
set(AllTests ${AllTests} ${RunTargetName} PARENT_SCOPE)
set(AllTestResults ${AllTestResults} ${test_name}.xml PARENT_SCOPE)
endfunction()

0 comments on commit cec3c38

Please sign in to comment.