# Define the API to add system tests in dune. The most # important function is :ref:`add_dune_system_test`, which # aims at doing all the work in one line. If you want # to split dynamic and static variations manually, use # both :ref:`add_static_variants` and :ref:`add_system_test_per_target`. # # .. cmake_function:: add_static_variants # # .. cmake_param:: SOURCE # :multi: # :required: # # The source files for the executables to generate. # # .. cmake_param:: BASENAME # :single: # :required: # # The basename for the given executables. The names of the # actual executables is generated by appending the `__exec_suffix` # key from the meta ini file to this basename (underscore separated). # Try to avoid using a given basename more than once in a project. # # .. cmake_param:: INIFILE # :single: # :required: # # The meta ini file, whose `__static` section is used to # define the executables to add. See :ref:`introductionmetaini` # for details on how to write such meta ini files. # # .. cmake_param:: CREATED_TARGETS # :single: # :required: # # Variable to store the list of generated targets in the outer scope. # Use this to manually tune generated targets after generation. # # .. cmake_param:: DEBUG # :option: # # Set this option to get verbose output from the generation process. # # Create a number of executables from the static information given in # meta ini file. The special section `__static` of the meta ini file is # relevant for this. Any variables you define in that section are interpreted # as preprocessor definitions. # # .. cmake_function:: add_system_test_per_target # # .. cmake_param:: TARGET # :multi: # :required: # # The target that specifies the executable that should be used for # the test. If multiple targets are given, each of them will be connected # with each ini file. # # .. cmake_param:: INIFILE # :single: # :required: # # The meta ini file, that describes the dynamic # variations of the systemtest. See :ref:`introductionmetaini` # for details on how to write such meta ini files. # # .. cmake_param:: SCRIPT # :single: # # The python wrapper script around the test. Defaults to :code:`call_executable.py`, # which essentially forwards the return code of the program run. # Changing this parameter to a different python wrapper enables more # involved, numerics-aware testing methods. Check :ref:`thewrappers` # for details on pre-implemented tools and on how to # write your own ones. # # .. cmake_param:: TARGETBASENAME # :single: # # This parameter is only for internal usage. # # Given a set of executables (givne as cmake targets), a number of tests is # added. The given meta ini file is expanded and each dynamic variant is # connected with each given executable. # # .. cmake_function:: dune_add_system_test # # .. cmake_param:: SOURCE # :multi: # :required: # # The source files for the executables to generate. # # .. cmake_param:: BASENAME # :single: # :required: # # The basename for the generated tests. The names of the # actual tests is generated by concatenating the # key from the meta ini file to this basename (underscore separated). # Try to avoid using a given basename more than once in a project. # # .. cmake_param:: INIFILE # :single: # :required: # # The meta ini file, that describes the dynamic and static # variations of the systemtest. See :ref:`introductionmetaini` # for details on how to write such meta ini files. # # .. cmake_param:: CREATED_TARGETS # :single: # :required: # # Variable to store the list of generated targets in the outer scope. # Use this to manually tune generated targets after generation. # # .. cmake_param:: SCRIPT # :single: # # The python wrapper script around the test. Defaults to :code:`call_executable.py`, # which essentially forwards the return code of the program run. # Changing this parameter to a different python wrapper enables more # involved, numerics-aware testing methods. Check :ref:`thewrappers` for details # on pre-implemented tools and on how to write your own ones. # # .. cmake_param:: DEBUG # :option: # # Set this option to get verbose output from the generation process. # # .. cmake_param:: NO_TESTS # :option: # # Set to avoid the adding of tests. Used to implement :ref:`dune_expand_metaini`. # # A one-line solution to adding system tests to the build system. # Internally, this reuses the functions :ref:`add_static_variants` and # :ref:`add_system_test_per_target`. # function(add_static_variants) # parse the parameter list set(OPTION DEBUG) set(SINGLE BASENAME INIFILE CREATED_TARGETS) set(MULTI SOURCE) cmake_parse_arguments(STATVAR "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(STATVAR_UNPARSED_ARGUMENTS) message(WARNING "add_static_variants: Encountered unparsed arguments: This often indicates typos in named arguments") endif() # Configure a bogus file from the meta ini file. This is a trick to retrigger configuration on meta ini changes. configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${STATVAR_INIFILE} ${CMAKE_CURRENT_BINARY_DIR}/tmp_${STATVAR_INIFILE}) # get the static information from the ini file # TODO maybe check whether an absolute path has been given for a mini file execute_process(COMMAND ${CMAKE_BINARY_DIR}/dune-env dune_extract_static.py --ini ${CMAKE_CURRENT_SOURCE_DIR}/${STATVAR_INIFILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} OUTPUT_VARIABLE output) parse_python_data(PREFIX STATINFO INPUT "${output}") # iterate over the static configurations foreach(conf ${STATINFO___CONFIGS}) # determine the target name: in case of only one config, omit the underscore. set(tname ${STATVAR_BASENAME}) if(NOT ${conf} STREQUAL "__empty") set(tname ${tname}_${conf}) endif() # add the executable with that configurations if(NOT TARGET ${tname}) # evaluate all the discarding conditions that have been provided! set(PROCEED TRUE) foreach(condition ${STATINFO_${conf}___GUARDS}) if(NOT ${condition}) set(PROCEED FALSE) endif() endforeach() if(PROCEED) add_executable(${tname} "${STATVAR_SOURCE}") # treat compile definitions foreach(cd ${STATINFO___COMPILE_DEFINITIONS}) target_compile_definitions(${tname} PUBLIC "${cd}=${STATINFO_${conf}_${cd}}") endforeach() # maybe output debug information if(${STATVAR_DEBUG}) message("Generated target ${tname}") get_property(cd TARGET ${tname} PROPERTY COMPILE_DEFINITIONS) message(" with COMPILE_DEFINITIONS: ${cd}") endif() # And append the target to the list of created targets list(APPEND targetlist "${tname}") endif() endif() if(${STATVAR_DEBUG}) message("Generating target ${tname} skipped because it already existed!") endif() endforeach() # export the list of created targets set(${STATVAR_CREATED_TARGETS} ${targetlist} PARENT_SCOPE) endfunction() function(add_system_test_per_target) # parse arguments to function call set(OPTION DEBUG) set(SINGLE INIFILE SCRIPT TARGETBASENAME) set(MULTI TARGET) cmake_parse_arguments(TARGVAR "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(TARGVAR_UNPARSED_ARGUMENTS) message(WARNING "add_system_test_per_target: Encountered unparsed arguments: This often indicates typos in named arguments") endif() # set a default for the script. call_executable.py just calls the executable. # There, it is also possible to hook in things depending on the inifile if(NOT TARGVAR_SCRIPT) set(TARGVAR_SCRIPT dune_execute.py) endif() # expand the given meta ini file into the build tree execute_process(COMMAND ${CMAKE_BINARY_DIR}/dune-env dune_expand_metaini.py --cmake --ini ${CMAKE_CURRENT_SOURCE_DIR}/${TARGVAR_INIFILE} --dir ${CMAKE_CURRENT_BINARY_DIR} OUTPUT_VARIABLE output) parse_python_data(PREFIX iniinfo INPUT "${output}") # add the tests for all targets foreach(target ${TARGVAR_TARGET}) foreach(inifile ${iniinfo_names}) if(${TARGVAR_DEBUG}) message(" Adding a target with executable ${target} and inifile ${inifile}...") endif() # Somehow the test have to be named, although the naming scheme is not relevant for # the selection of tests to run on the server side. For the moment we combine the # executable target name with the ini file name. get_filename_component(ininame ${inifile} NAME_WE) # check whether something needs to be done. This is either when our target is matching # the given suffix, or when TARGETBASENAME isnt given (this indicates stand-alone usage) # or in case no suffix is given (we have only one target) when the target is matching the # target basename set(DOSOMETHING FALSE) # ugly CMake bug gets fixed by adding a random prefix to the compared strings if("compare_${TARGVAR_TARGETBASENAME}" STREQUAL "compare_${target}") set(DOSOMETHING TRUE) endif() if("compare_${TARGVAR_TARGETBASENAME}_${iniinfo_${inifile}_suffix}" STREQUAL "compare_${target}") set(DOSOMETHING TRUE) endif() if(NOT DEFINED TARGVAR_TARGETBASENAME) set(DOSOMETHING TRUE) endif() if(${TARGVAR_DEBUG}) message(" -- ${DOSOMETHING}") endif() # get the extension of the ini file (can be user defined) get_filename_component(iniext ${inifile} EXT) if(${DOSOMETHING}) if(NOT ${MPI_CXX_FOUND}) add_test(NAME ${target}_${ininame} COMMAND ${CMAKE_BINARY_DIR}/dune-env ${TARGVAR_SCRIPT} --exec ${target} --ini "${CMAKE_CURRENT_BINARY_DIR}/${ininame}${iniext}" --source ${CMAKE_CURRENT_SOURCE_DIR} ) else() add_test(NAME ${target}_${ininame} COMMAND ${CMAKE_BINARY_DIR}/dune-env ${TARGVAR_SCRIPT} --exec ${target} --ini "${CMAKE_CURRENT_BINARY_DIR}/${ininame}${iniext}" --source ${CMAKE_CURRENT_SOURCE_DIR} --mpi-exec "${MPIEXEC}" --mpi-numprocflag=${MPIEXEC_NUMPROC_FLAG} --mpi-preflags "${MPIEXEC_PREFLAGS}" --mpi-postflags "${MPIEXEC_POSTFLAGS}" --max-processors=${DUNE_MAX_TEST_CORES} ) endif() set_property(TEST ${target}_${ininame} PROPERTY LABELS ${iniinfo_labels_${ininame}} DUNE_SYSTEMTEST) set_tests_properties(${target}_${ininame} PROPERTIES SKIP_RETURN_CODE "77") endif() endforeach() endforeach() endfunction() function(dune_add_system_test) # parse arguments set(OPTION DEBUG NO_TESTS) set(SINGLE INIFILE BASENAME SCRIPT) set(MULTI SOURCE TARGET CREATED_TARGETS) cmake_parse_arguments(SYSTEMTEST "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(SYSTEMTEST_UNPARSED_ARGUMENTS) message(WARNING "dune_add_system_test: Encountered unparsed arguments: This often indicates typos in named arguments") endif() # construct a string containg DEBUG to pass the debug flag to the other macros set(DEBUG "") if(SYSTEMTEST_DEBUG) set(DEBUG "DEBUG") endif() # set a default for the script. call_executable.py just calls the executable. # There, it is also possible to hook in things depending on the inifile if(NOT SYSTEMTEST_SCRIPT) set(SYSTEMTEST_SCRIPT dune_execute.py) endif() # we provide two signatures: either a source(s) is given or a target(s) if(SYSTEMTEST_SOURCE AND SYSTEMTEST_TARGET) message(FATAL_ERROR "Use either the SOURCE or the TARGET signature!") endif() if(NOT SYSTEMTEST_SOURCE AND NOT SYSTEMTEST_TARGET) message(FATAL_ERROR "Specify either the SOURCE or the TARGET argument!") endif() if(SYSTEMTEST_SOURCE) # The above macros have been written in a way that allows us to use them # combined. The TARGETBASENAME parameter is introduced for that. add_static_variants(SOURCE ${SYSTEMTEST_SOURCE} BASENAME ${SYSTEMTEST_BASENAME} INIFILE ${SYSTEMTEST_INIFILE} CREATED_TARGETS targetlist ${DEBUG}) # export the targetlist generated by add_static_variants set(${SYSTEMTEST_CREATED_TARGETS} ${targetlist} PARENT_SCOPE) # If the NO_TESTS option is given, we discard the targetlist here # that will prohibit the addition of tests in the implementation of # add_system_test_per_target. if(SYSTEMTEST_NO_TESTS) set(targetlist) endif() add_system_test_per_target(INIFILE ${SYSTEMTEST_INIFILE} TARGET ${targetlist} SCRIPT ${SYSTEMTEST_SCRIPT} ${DEBUG} TARGETBASENAME ${SYSTEMTEST_BASENAME}) else() execute_process(COMMAND ${CMAKE_BINARY_DIR}/dune-env dune_has_static_section.py --ini ${CMAKE_CURRENT_SOURCE_DIR}/${SYSTEMTEST_INIFILE} RESULT_VARIABLE res) if(${res}) message(STATUS "The meta ini file specifies static variations!") message(FATAL_ERROR "The TARGET signature can be only used for dynamic variations.") endif() if(SYSTEMTEST_BASENAME) message(WARNING "A BASENAME is given for the TARGET signature. The argument is ignored!") endif() # the target signature is effectively a convenience function for the dyanmic macro # be careful not to have a static section in the meta ini file! set(${SYSTEMTEST_CREATED_TARGETS} ${SYSTEMTEST_TARGET} PARENT_SCOPE) add_system_test_per_target(INIFILE ${SYSTEMTEST_INIFILE} TARGET ${SYSTEMTEST_TARGET} SCRIPT ${SYSTEMTEST_SCRIPT} ${DEBUG}) endif() endfunction()