Skip to content

Commit

Permalink
run C++ unit tests during build option, enabled if devMode=ON (#640)
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilipDeegan authored Jan 21, 2022
1 parent 6b2dac0 commit 5aad770
Show file tree
Hide file tree
Showing 15 changed files with 216 additions and 182 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ compile_commands.json
phare_outputs*
CMakeLists.txt.user
.log
tools/cmake.sh
.cmake.*
perf.*
**/*.h5
.vscode

5 changes: 2 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ if(PHARE_WITH_CCACHE)
endif()
####

include("${PHARE_PROJECT_DIR}/res/cmake/test.cmake")
include("${PHARE_PROJECT_DIR}/res/cmake/bench.cmake")

#*******************************************************************************
# PHARE source code
add_subdirectory(src/core)
Expand All @@ -53,5 +50,7 @@ add_subdirectory(src/python3)
add_subdirectory(src/phare)
#*******************************************************************************

include("${PHARE_PROJECT_DIR}/res/cmake/test.cmake")
include("${PHARE_PROJECT_DIR}/res/cmake/bench.cmake")

print_phare_options()
186 changes: 185 additions & 1 deletion res/cmake/def.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ endif(withIPO)

set (PHARE_WITH_CCACHE FALSE)
if(devMode) # -DdevMode=ON
set(testDuringBuild ON)

# Having quotes on strings here has lead to quotes being added to the compile string, so avoid.

set (_Werr ${PHARE_WERROR_FLAGS} -Wall -Wextra -pedantic -Werror -Wno-unused-variable -Wno-unused-parameter)
Expand Down Expand Up @@ -52,7 +54,14 @@ function(phare_sanitize_ san cflags )
endfunction(phare_sanitize_)

if (asan) # -Dasan=ON
phare_sanitize_("-fsanitize=address -shared-libsan" "-fno-omit-frame-pointer" )
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
phare_sanitize_("-fsanitize=address" "-fno-omit-frame-pointer" )
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
phare_sanitize_("-fsanitize=address -shared-libsan" "-fno-omit-frame-pointer" )
else()
message(FATAL_ERROR "ASAN Unhandled compiler: ${CMAKE_CXX_COMPILER_ID}")
endif()
set(testDuringBuild OFF) # can need LD_PRELOAD/etc
endif(asan)

if (ubsan) # -Dubsan=ON
Expand All @@ -61,4 +70,179 @@ endif(ubsan)

# msan is not supported - it's not practical to configure - use valgrind

# test functions below

# public test functions
#
# add_phare_test($binary $directory)
# execute binary in target directory, with mpirun when -DtestMPI=ON
#
# add_python3_test($name $file $directory)
# launch python3 file described by name in target directory, with mpirun when -DtestMPI=ON
#
# add_no_mpi_phare_test($binary $directory)
# execute binary in target directory, does not run when -DtestMPI=ON
#
# add_no_mpi_python3_test($name $file $directory)
# launch python3 file described by name in target directory, does not run when -DtestMPI=ON
#
# phare_exec(level target exe directory)
# execute exe identified by target in directory
# if level >= PHARE_EXEC_LEVEL_MIN AND level <= PHARE_EXEC_LEVEL_MAX
#
# phare_python3_exec(level target file directory $ARGS)
# execute file identified by target in directory
# if level >= PHARE_EXEC_LEVEL_MIN AND level <= PHARE_EXEC_LEVEL_MAX
#
# Note to developers - do not use cmake variable function arguments for functions
# phare_python3_exec
# phare_mpi_python3_exec
# if these function calls are to files executing python unit tests as they will interfere

if (test AND ${PHARE_EXEC_LEVEL_MIN} GREATER 0) # 0 = no tests

if (NOT DEFINED PHARE_MPI_PROCS)
set(PHARE_MPI_PROCS 1)
if(testMPI)
set(PHARE_MPI_PROCS 2)
endif()
endif()

function(set_exe_paths_ binary)
set_property(TEST ${binary} PROPERTY ENVIRONMENT "PYTHONPATH=${PHARE_PYTHONPATH}")
# ASAN detects leaks by default, even in system/third party libraries
set_property(TEST ${binary} APPEND PROPERTY ENVIRONMENT "ASAN_OPTIONS=detect_leaks=0")
endfunction(set_exe_paths_)

function(add_phare_test_ binary directory)
target_compile_options(${binary} PRIVATE ${PHARE_WERROR_FLAGS} -DPHARE_HAS_HIGHFIVE=${PHARE_HAS_HIGHFIVE})
set_exe_paths_(${binary})
set_property(TEST ${binary} APPEND PROPERTY ENVIRONMENT GMON_OUT_PREFIX=gprof.${binary})
set_property(TEST ${binary} APPEND PROPERTY ENVIRONMENT PHARE_MPI_PROCS=${PHARE_MPI_PROCS})
if(testDuringBuild)
add_custom_command(
TARGET ${binary}
POST_BUILD
WORKING_DIRECTORY ${directory}
COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> -R \"^${binary}$$\" --output-on-failures
)
endif(testDuringBuild)
endfunction(add_phare_test_)

function(add_no_mpi_phare_test binary directory)
if(NOT testMPI OR (testMPI AND forceSerialTests))
add_test(NAME ${binary} COMMAND ./${binary} WORKING_DIRECTORY ${directory})
add_phare_test_(${binary} ${directory})
else()
# this prevents building targets even when added via "add_executable"
set_target_properties(${binary} PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
endif()
endfunction(add_no_mpi_phare_test)

function(add_no_mpi_python3_test name file directory)
if(NOT testMPI OR (testMPI AND forceSerialTests))
add_test(NAME py3_${name} COMMAND python3 -u ${file} WORKING_DIRECTORY ${directory})
set_exe_paths_(py3_${name})
endif()
endfunction(add_no_mpi_python3_test)

if(testMPI)
function(add_phare_test binary directory)
add_test(NAME ${binary} COMMAND mpirun -n ${PHARE_MPI_PROCS} ./${binary} WORKING_DIRECTORY ${directory})
add_phare_test_(${binary} ${directory})
endfunction(add_phare_test)

function(add_python3_test name file directory)
add_test(NAME py3_${name} COMMAND mpirun -n ${PHARE_MPI_PROCS} python3 -u ${file} WORKING_DIRECTORY ${directory})
set_exe_paths_(py3_${name})
endfunction(add_python3_test)

function(add_mpi_python3_test N name file directory)
add_test(NAME py3_${name}_mpi_n_${N} COMMAND mpirun -n ${N} python3 ${file} WORKING_DIRECTORY ${directory})
set_exe_paths_(py3_${name}_mpi_n_${N})
endfunction(add_mpi_python3_test)

else()
function(add_phare_test binary directory)
add_no_mpi_phare_test(${binary} ${directory})
endfunction(add_phare_test)

function(add_python3_test name file directory)
add_no_mpi_python3_test(${name} ${file} ${directory})
endfunction(add_python3_test)

function(add_mpi_python3_test N name file directory)
# do nothing
endfunction(add_mpi_python3_test)
endif(testMPI)


function(add_phare_build_test binary directory)
endfunction(add_phare_build_test)


if(DEFINED GTEST_ROOT)
set(GTEST_ROOT ${GTEST_ROOT} CACHE PATH "Path to googletest")
find_package(GTest REQUIRED)
set(GTEST_LIBS GTest::GTest GTest::Main)
else()
set(GTEST_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/subprojects/googletest)

if (NOT EXISTS ${GTEST_ROOT})
execute_process(COMMAND ${Git} clone https://github.com/google/googletest ${GTEST_ROOT})
endif()

add_subdirectory(subprojects/googletest)
set(GTEST_INCLUDE_DIRS
$<BUILD_INTERFACE:${gtest_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${gmock_SOURCE_DIR}/include>)
set(GTEST_LIBS gtest gmock)

endif()

function(phare_exec level target exe directory)
if(${level} GREATER_EQUAL ${PHARE_EXEC_LEVEL_MIN} AND ${level} LESS_EQUAL ${PHARE_EXEC_LEVEL_MAX})
add_test(NAME ${target} COMMAND ${exe} WORKING_DIRECTORY ${directory})
endif()
endfunction(phare_exec)
# use
# phare_exec(1 test_id ./binary ${CMAKE_CURRENT_BINARY_DIR})

function(phare_python3_exec level target file directory)
if(${level} GREATER_EQUAL ${PHARE_EXEC_LEVEL_MIN} AND ${level} LESS_EQUAL ${PHARE_EXEC_LEVEL_MAX})
string (REPLACE ";" " " CLI_ARGS "${ARGN}")
add_test(NAME py3_${target} COMMAND python3 -u ${file} ${CLI_ARGS} WORKING_DIRECTORY ${directory})
set_exe_paths_(py3_${target})
endif()
endfunction(phare_python3_exec)
# use
# phare_python3_exec(1 test_id script.py ${CMAKE_CURRENT_BINARY_DIR} $ARGS)


function(phare_mpi_python3_exec level N target file directory)
if(${level} GREATER_EQUAL ${PHARE_EXEC_LEVEL_MIN} AND ${level} LESS_EQUAL ${PHARE_EXEC_LEVEL_MAX})
string (REPLACE ";" " " CLI_ARGS "${ARGN}")
if(${N} EQUAL 1)
add_test(
NAME py3_${target}
COMMAND python3 -u ${file} ${CLI_ARGS}
WORKING_DIRECTORY ${directory})
set_exe_paths_(py3_${target})
else()
add_test(
NAME py3_${target}_mpi_n_${N}
COMMAND mpirun -n ${N} python3 -u ${file} ${CLI_ARGS}
WORKING_DIRECTORY ${directory})
set_exe_paths_(py3_${target}_mpi_n_${N})
endif()
endif()
endfunction(phare_mpi_python3_exec)
# use
# phare_mpi_python3_exec(1 2 test_id script.py ${CMAKE_CURRENT_BINARY_DIR} $ARGS)

set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIRS} ${PHARE_PROJECT_DIR})

enable_testing()

endif()

3 changes: 3 additions & 0 deletions res/cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ option(withCaliper "Use LLNL Caliper" OFF)
# -DlowResourceTests=ON
option(lowResourceTests "Disable heavy tests for CI (2d/3d/etc" OFF)

# -DtestDuringBuild=ON enabled if devMode=ON, disabled if asan=ON (needs LD_PRELOAD)
option(testDuringBuild "Runs C++ unit tests after they are built" OFF)


# Controlling the activation of tests
if (NOT DEFINED PHARE_EXEC_LEVEL_MIN)
Expand Down
Loading

0 comments on commit 5aad770

Please sign in to comment.