Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
pull_request:
branches: [ main ]

env:
DEBIAN_FRONTEND: noninteractive
CMAKE_GENERATOR: Ninja

concurrency:
group: ${{ github.head_ref || github.run_id }}
cancel-in-progress: true
Expand Down Expand Up @@ -56,7 +60,6 @@ jobs:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
CXX_STANDARD: ${{ matrix.cxx_standard }}
CMAKE_GENERATOR: Ninja
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build_type}}

- name: Build Unit Tests
Expand Down Expand Up @@ -133,7 +136,6 @@ jobs:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
CXX_STANDARD: ${{ matrix.cxx_standard }}
CMAKE_GENERATOR: Ninja
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build_type}}

- name: Build Unit Tests
Expand Down Expand Up @@ -163,8 +165,8 @@ jobs:
CC: "/usr/lib/llvm-15/bin/clang"
CXX: "/usr/lib/llvm-15/bin/clang++"
CXX_STANDARD: 20
CMAKE_GENERATOR: Ninja
run: cmake -B ${{github.workspace}}/build -DCLANG_TOOLS_PATH=/usr/lib/llvm-15/bin
CLANG_TOOLS_PATH: "/usr/lib/llvm-15/bin"
run: cmake -B ${{github.workspace}}/build

- name: Run quality checks
run: cmake --build ${{github.workspace}}/build -t quality
Expand All @@ -184,8 +186,8 @@ jobs:
CC: "/usr/lib/llvm-15/bin/clang"
CXX: "/usr/lib/llvm-15/bin/clang++"
CXX_STANDARD: 20
CMAKE_GENERATOR: Ninja
run: cmake -B ${{github.workspace}}/build -DSANITIZERS=undefined,address
SANITIZERS: "undefined,address"
run: cmake -B ${{github.workspace}}/build

- name: Build Unit Tests
run: cmake --build ${{github.workspace}}/build -t unit_tests
Expand All @@ -202,6 +204,10 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Install build tools
run: |
sudo apt install -y ninja-build

- name: Configure CMake
run: cmake -B ${{github.workspace}}/build

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
/venv
/examples/hello_world/build
/.vscode
/toolchains
CMakePresets.json
49 changes: 9 additions & 40 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.20)

project(
cib
Expand All @@ -15,8 +15,13 @@ if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
)
endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS
ON
CACHE BOOL "Export compile commands to compile_commands.json." FORCE)

include(cmake/dependencies.cmake)
include(cmake/libraries.cmake)
include(cmake/quality.cmake)

add_versioned_package("gh:fmtlib/fmt#9.1.0")

Expand All @@ -32,16 +37,10 @@ target_compile_options(
$<$<CXX_COMPILER_ID:Clang>:-Wno-gnu-zero-variadic-macro-arguments>)

if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
if(CLANG_TOOLS_PATH)
list(APPEND CMAKE_PROGRAM_PATH ${CLANG_TOOLS_PATH})
endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(cmake/sanitizers.cmake)
include(cmake/test.cmake)
include(cmake/warnings.cmake)
clang_tidy_interface(cib)

# Enable functional and performance test suites.
enable_testing()
add_subdirectory(test)
add_subdirectory(benchmark)
add_subdirectory(examples)
Expand All @@ -64,39 +63,9 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)

add_custom_target(release_header
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/include/cib/cib.hpp)

add_versioned_package(
NAME
Format.cmake
VERSION
1.7.3
GITHUB_REPOSITORY
TheLartians/Format.cmake
OPTIONS
"CMAKE_FORMAT_EXCLUDE cmake/CPM.cmake")

add_custom_target(quality)
add_dependencies(quality check-clang-format check-cmake-format)

if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
find_program(CLANG_TIDY_PROGRAM "clang-tidy")
if(CLANG_TIDY_PROGRAM)
add_custom_target(clang-tidy)
include(cmake/clang-tidy.cmake)
clang_tidy_interface(cib)
else()
message(STATUS "clang-tidy not found. Adding dummy target.")
set(CLANG_TIDY_NOT_FOUND_COMMAND_ARGS
COMMAND ${CMAKE_COMMAND} -E echo
"Cannot run clang-tidy because clang-tidy not found." COMMAND
${CMAKE_COMMAND} -E false)
add_custom_target(clang-tidy ${CLANG_TIDY_NOT_FOUND_COMMAND_ARGS})
endif()
add_dependencies(quality clang-tidy)
endif()
endif()

if($ENV{SINGLE_HEADER})
if(DEFINED ENV{SINGLE_HEADER})
add_dependencies(cib release_header)

target_include_directories(
Expand Down
9 changes: 6 additions & 3 deletions cmake/clang-tidy.cmake
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
set(CREATE_CLANG_TIDIABLE_SCRIPT
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/create-clang-tidiable.sh"
CACHE STRING "")

function(clang_tidy_header HEADER TARGET)
file(RELATIVE_PATH CT_NAME ${CMAKE_SOURCE_DIR} ${HEADER})
string(REPLACE "/" "_" CT_NAME ${CT_NAME})
get_filename_component(CT_NAME ${CT_NAME} NAME_WLE)
set(CT_NAME "clang_tidy_${CT_NAME}")
set(CT_NAME "clang-tidy_${CT_NAME}")
set(CPP_NAME
"${CMAKE_BINARY_DIR}/generated-sources/${TARGET}/${CT_NAME}.cpp")

add_custom_command(
OUTPUT "${CPP_NAME}"
COMMAND ${CMAKE_COMMAND} -E make_directory
"${CMAKE_BINARY_DIR}/generated-sources/${TARGET}"
COMMAND ${CMAKE_SOURCE_DIR}/cmake/create-clang-tidiable.sh ${CPP_NAME}
${HEADER}
COMMAND "${CREATE_CLANG_TIDIABLE_SCRIPT}" ${CPP_NAME} ${HEADER}
DEPENDS ${HEADER} ${CMAKE_SOURCE_DIR}/.clang-tidy)

add_library(${CT_NAME} EXCLUDE_FROM_ALL ${CPP_NAME})
Expand Down
45 changes: 45 additions & 0 deletions cmake/quality.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
function(clang_tidy_interface TARGET)
message(
STATUS
"clang_tidy_interface(${TARGET}) is disabled because CMAKE_CXX_COMPILER_ID is ${CMAKE_CXX_COMPILER_ID}."
)
endfunction()

if(PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
if(DEFINED ENV{CLANG_TOOLS_PATH})
list(APPEND CMAKE_PROGRAM_PATH $ENV{CLANG_TOOLS_PATH})
endif()

include(cmake/sanitizers.cmake)
include(cmake/test.cmake)
include(cmake/warnings.cmake)

add_versioned_package(
NAME
Format.cmake
VERSION
1.7.3
GITHUB_REPOSITORY
TheLartians/Format.cmake
OPTIONS
"CMAKE_FORMAT_EXCLUDE cmake/CPM.cmake")

add_custom_target(quality)
add_dependencies(quality check-clang-format check-cmake-format)

if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
find_program(CLANG_TIDY_PROGRAM "clang-tidy")
if(CLANG_TIDY_PROGRAM)
add_custom_target(clang-tidy)
include(cmake/clang-tidy.cmake)
else()
message(STATUS "clang-tidy not found. Adding dummy target.")
set(CLANG_TIDY_NOT_FOUND_COMMAND_ARGS
COMMAND ${CMAKE_COMMAND} -E echo
"Cannot run clang-tidy because clang-tidy not found." COMMAND
${CMAKE_COMMAND} -E false)
add_custom_target(clang-tidy ${CLANG_TIDY_NOT_FOUND_COMMAND_ARGS})
endif()
add_dependencies(quality clang-tidy)
endif()
endif()
4 changes: 4 additions & 0 deletions cmake/sanitizers.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
add_library(sanitizers INTERFACE)

if(DEFINED ENV{SANITIZERS})
set(SANITIZERS $ENV{SANITIZERS})
endif()

if(SANITIZERS)
target_compile_options(
sanitizers
Expand Down
107 changes: 99 additions & 8 deletions cmake/test.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
enable_testing()
add_custom_target(unit_tests)

if(DEFINED ENV{CXX_STANDARD} AND NOT $ENV{CXX_STANDARD} EQUAL "")
Expand All @@ -7,15 +6,57 @@ else()
set(CMAKE_CXX_STANDARD 17)
endif()

add_versioned_package("gh:catchorg/Catch2@3.1.1")
add_versioned_package("gh:google/googletest#release-1.12.1")
macro(get_catch2)
if(NOT DEFINED CPM_GOT_CATCH)
add_versioned_package("gh:catchorg/Catch2@3.3.1")
list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras)
include(Catch)
set(CPM_GOT_CATCH 1)
endif()
endmacro()

macro(get_gtest)
if(NOT DEFINED CPM_GOT_GTEST)
add_versioned_package("gh:google/googletest@1.13.0")
include(GoogleTest)
set(CPM_GOT_GTEST 1)
endif()
endmacro()

list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras)
include(Catch)
include(GoogleTest)
macro(get_gunit)
get_gtest()
if(NOT DEFINED CPM_GOT_GUNIT)
add_versioned_package(
NAME
gunit
GIT_TAG
d02ec96
GITHUB_REPOSITORY
cpp-testing/GUnit
DOWNLOAD_ONLY
YES)
set(CPM_GOT_GUNIT 1)
endif()
endmacro()

macro(add_boost_di)
if(NOT DEFINED CPM_GOT_BOOST_DI)
add_versioned_package("gh:boost-ext/di#9866a4a")
set(CPM_GOT_BOOST_DI 1)
endif()
endmacro()

macro(add_gherkin)
if(NOT DEFINED CPM_GOT_GHERKIN)
add_subdirectory(
${gunit_SOURCE_DIR}/libs/gherkin-cpp
${gunit_BINARY_DIR}/libs/gherkin-cpp EXCLUDE_FROM_ALL SYSTEM)
set(CPM_GOT_GHERKIN 1)
endif()
endmacro()

function(add_unit_test name)
set(options CATCH2 GTEST)
set(options CATCH2 GTEST GUNIT)
set(multiValueArgs FILES INCLUDE_DIRECTORIES LIBRARIES SYSTEM_LIBRARIES)
cmake_parse_arguments(UNIT "${options}" "" "${multiValueArgs}" ${ARGN})

Expand All @@ -26,16 +67,29 @@ function(add_unit_test name)
target_link_libraries(${name} PRIVATE sanitizers)

if(UNIT_CATCH2)
get_catch2()
catch_discover_tests(${name})
target_link_libraries_system(${name} PRIVATE Catch2::Catch2WithMain)
set(target_test_command $<TARGET_FILE:${name}> "--order" "rand")
elseif(UNIT_GTEST)
get_gtest()
gtest_discover_tests(${name})
target_link_libraries_system(${name} PRIVATE gmock gtest gmock_main)
set(target_test_command $<TARGET_FILE:${name}> "--gtest_shuffle")
elseif(UNIT_GUNIT)
get_gunit()
add_boost_di()
gtest_discover_tests(${name})
target_include_directories(
${name} SYSTEM
PRIVATE ${gunit_SOURCE_DIR}/include
${gunit_SOURCE_DIR}/libs/json/single_include/nlohmann)
target_link_libraries_system(${name} PRIVATE gtest_main gmock_main
Boost.DI)
set(target_test_command $<TARGET_FILE:${name}> "--gtest_shuffle")
else()
add_test(NAME ${name} COMMAND ${target_test_command})
set(target_test_command $<TARGET_FILE:${name}>)
add_test(NAME ${name} COMMAND ${target_test_command})
endif()

add_custom_target(all_${name} ALL DEPENDS run_${name})
Expand All @@ -48,3 +102,40 @@ function(add_unit_test name)

add_dependencies(unit_tests "run_${name}")
endfunction()

function(add_feature_test name)
set(singleValueArgs FEATURE)
set(multiValueArgs FILES INCLUDE_DIRECTORIES LIBRARIES SYSTEM_LIBRARIES)
cmake_parse_arguments(FEAT "${options}" "${singleValueArgs}"
"${multiValueArgs}" ${ARGN})

add_executable(${name} ${FEAT_FILES})
target_include_directories(${name} PRIVATE ${FEAT_INCLUDE_DIRECTORIES})
target_link_libraries(${name} PRIVATE ${FEAT_LIBRARIES})
target_link_libraries_system(${name} PRIVATE ${FEAT_SYSTEM_LIBRARIES})
target_link_libraries(${name} PRIVATE sanitizers)

get_gunit()
add_gherkin()
add_boost_di()
gtest_discover_tests(${name})
target_include_directories(
${name} SYSTEM
PRIVATE ${gunit_SOURCE_DIR}/include
${gunit_SOURCE_DIR}/libs/json/single_include/nlohmann)
target_link_libraries_system(${name} PRIVATE gtest_main gmock_main
gherkin-cpp Boost.DI)
set(target_test_command $<TARGET_FILE:${name}>)

add_custom_target(all_${name} ALL DEPENDS run_${name})
add_custom_target(run_${name} DEPENDS ${name}.passed ${FEAT_FEATURE})
get_filename_component(FEATURE_FILE ${FEAT_FEATURE} ABSOLUTE)
add_custom_command(
OUTPUT ${name}.passed
COMMAND ${CMAKE_COMMAND} -E env SCENARIO="${FEATURE_FILE}"
${target_test_command}
COMMAND ${CMAKE_COMMAND} "-E" "touch" "${name}.passed"
DEPENDS ${name})

add_dependencies(unit_tests "run_${name}")
endfunction()