########################################################################## # Regression Testing Support for Boost # ########################################################################## # Copyright (C) 2007-8 Douglas Gregor # # Copyright (C) 2007-8 Troy D. Straszheim # # # # Distributed under the Boost Software License, Version 1.0. # # See accompanying file LICENSE_1_0.txt or copy at # # http://www.boost.org/LICENSE_1_0.txt # ########################################################################## # This file provides a set of CMake macros that support regression # testing for Boost libraries. For each of the test macros below, the # first argument, testname, states the name of the test that will be # created. If no other arguments are provided, the source file # testname.cpp will be used as the source file; otherwise, source # files should be listed immediately after the name of the test. # # The macros for creating regression tests are: # boost_test_run: Builds an executable and runs it as a test. The test # succeeds if it builds and returns 0 when executed. # # boost_test_run_fail: Builds an executable and runs it as a test. The # test succeeds if it builds but returns a non-zero # exit code when executed. # # boost_test_compile: Tests that the given source file compiles without # any errors. # # boost_test_compile_fail: Tests that the given source file produces # errors when compiled. # # boost_additional_test_dependencies: Adds needed include directories for # the tests. # User-controlled option that can be used to enable/disable regression # testing. By default, we disable testing, because most users won't # want or need to perform regression testing on Boost. The Boost build # is significantly faster when we aren't also building regression # tests. option(BUILD_REGRESSION_TESTS "Enable regression testing" OFF) if (BUILD_REGRESSION_TESTS) enable_testing() mark_as_advanced(BUILD_TESTING) option(TEST_INSTALLED_TREE "Enable testing of an already-installed tree" OFF) set(BOOST_TEST_LIBRARIES "" CACHE STRING "Semicolon-separated list of Boost libraries to test") if (TEST_INSTALLED_TREE) include("${CMAKE_INSTALL_PREFIX}/lib/Boost${BOOST_VERSION}/boost-targets.cmake") endif (TEST_INSTALLED_TREE) set(DART_TESTING_TIMEOUT=15 CACHE INTEGER "Timeout after this much madness") endif (BUILD_REGRESSION_TESTS) #------------------------------------------------------------------------------- # This macro adds additional include directories based on the dependencies of # the library being tested 'libname' and all of its dependencies. # # boost_additional_test_dependencies(libname # BOOST_DEPENDS libdepend1 libdepend2 ...) # # libname is the name of the boost library being tested. (signals) # # There is mandatory argument to the macro: # # BOOST_DEPENDS: The list of the extra boost libraries that the test suite will # depend on. You do NOT have to list those libraries already listed by the # module.cmake file as these will be used. # # # example usage: # boost_additional_test_dependencies(signals BOOST_DEPENDS test optional) # macro(boost_additional_test_dependencies libname) parse_arguments(BOOST_TEST "BOOST_DEPENDS" "" ${ARGN} ) # Get the list of libraries that this test depends on # Set THIS_PROJECT_DEPENDS_ALL to the set of all of its # dependencies, its dependencies' dependencies, etc., transitively. string(TOUPPER "BOOST_${libname}_DEPENDS" THIS_PROJECT_DEPENDS) set(THIS_TEST_DEPENDS_ALL ${libname} ${${THIS_PROJECT_DEPENDS}} ) set(ADDED_DEPS TRUE) while (ADDED_DEPS) set(ADDED_DEPS FALSE) foreach(DEP ${THIS_TEST_DEPENDS_ALL}) string(TOUPPER "BOOST_${DEP}_DEPENDS" DEP_DEPENDS) foreach(DEPDEP ${${DEP_DEPENDS}}) list(FIND THIS_TEST_DEPENDS_ALL ${DEPDEP} DEPDEP_INDEX) if (DEPDEP_INDEX EQUAL -1) list(APPEND THIS_TEST_DEPENDS_ALL ${DEPDEP}) set(ADDED_DEPS TRUE) endif() endforeach() endforeach() endwhile() # Get the list of dependencies for the additional libraries arguments foreach(additional_lib ${BOOST_TEST_BOOST_DEPENDS}) list(FIND THIS_TEST_DEPENDS_ALL ${additional_lib} DEPDEP_INDEX) if (DEPDEP_INDEX EQUAL -1) list(APPEND THIS_TEST_DEPENDS_ALL ${additional_lib}) set(ADDED_DEPS TRUE) endif() string(TOUPPER "BOOST_${additional_lib}_DEPENDS" THIS_PROJECT_DEPENDS) set(ADDED_DEPS TRUE) while (ADDED_DEPS) set(ADDED_DEPS FALSE) foreach(DEP ${THIS_TEST_DEPENDS_ALL}) string(TOUPPER "BOOST_${DEP}_DEPENDS" DEP_DEPENDS) foreach(DEPDEP ${${DEP_DEPENDS}}) list(FIND THIS_TEST_DEPENDS_ALL ${DEPDEP} DEPDEP_INDEX) if (DEPDEP_INDEX EQUAL -1) list(APPEND THIS_TEST_DEPENDS_ALL ${DEPDEP}) set(ADDED_DEPS TRUE) endif() endforeach() endforeach() endwhile() endforeach() foreach (include ${THIS_TEST_DEPENDS_ALL}) include_directories("${Boost_SOURCE_DIR}/libs/${include}/include") endforeach (include ${includes}) endmacro(boost_additional_test_dependencies libname) #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # This macro is an internal utility macro that helps parse the # arguments passed to the Boost testing commands. It will generally # not be used by Boost developers. # # boost_test_parse_args(testname # [source1 source2 ...] # [ARGS arg1 arg2... ] # [COMPILE_FLAGS compileflags] # [LINK_FLAGS linkflags] # [LINK_LIBS linklibs] # [DEPENDS libdepend1 libdepend2 ...] # [KNOWN_FAILURES string1 string2 ...] # [COMPILE] [RUN] [FAIL]) # # testname is the name of the test. The remaining arguments passed to # this macro will be parsed and categorized for the developer-level # test macros to use. # # Variables affected: # # BOOST_TEST_OKAY: Will be set to TRUE if it is okay to build and # run this test. # # BOOST_TEST_SOURCES: Will be populated with the set of source files # that should be used to compile this test. If the user has provided # source files, BOOST_TEST_SOURCES will contain those; otherwise, # BOOST_TEST_SOURCES will only contain "testname.cpp". # # BOOST_TEST_TESTNAME: A (hopefully) globally unique target name # for the test, constructed from PROJECT-testname-TAG # # BOOST_TEST_arg: Will be populated with the arguments provided for # the arguemnt "arg", where "arg" can be any of the extra arguments # specified above. # # macro(boost_test_parse_args testname) #message("boost_test_parse_args ${testname} ${ARGN}") set(BOOST_TEST_OKAY TRUE) set(BOOST_TEST_COMPILE_FLAGS "") parse_arguments(BOOST_TEST "BOOST_LIB;LINK_LIBS;LINK_FLAGS;DEPENDS;COMPILE_FLAGS;ARGS;EXTRA_OPTIONS;KNOWN_FAILURES" "COMPILE;RUN;LINK;FAIL;RELEASE;DEBUG" ${ARGN} ) # Check each of the dependencies to see if we can still build this # test. foreach(ARG ${BOOST_TEST_DEPENDS}) get_target_property(DEPEND_TYPE ${ARG} TYPE) get_target_property(DEPEND_LOCATION ${ARG} LOCATION) # If building static libraries is turned off, don't try to build # the test if (NOT BUILD_STATIC AND ${DEPEND_TYPE} STREQUAL "STATIC_LIBRARY") set(BOOST_TEST_OKAY FALSE) endif (NOT BUILD_STATIC AND ${DEPEND_TYPE} STREQUAL "STATIC_LIBRARY") # If building shared libraries is turned off, don't try to build # the test if (NOT BUILD_SHARED AND ${DEPEND_TYPE} STREQUAL "SHARED_LIBRARY") set(BOOST_TEST_OKAY FALSE) endif (NOT BUILD_SHARED AND ${DEPEND_TYPE} STREQUAL "SHARED_LIBRARY") endforeach(ARG ${BOOST_TEST_DEPENDS}) # Setup the SOURCES variables. If no sources are specified, use the # name of the test.cpp if (BOOST_TEST_DEFAULT_ARGS) set(BOOST_TEST_SOURCES ${BOOST_TEST_DEFAULT_ARGS}) else (BOOST_TEST_DEFAULT_ARGS) set(BOOST_TEST_SOURCES "${testname}.cpp") endif (BOOST_TEST_DEFAULT_ARGS) set(BOOST_TEST_TESTNAME "${PROJECT_NAME}-${testname}") #message("testname: ${BOOST_TEST_TESTNAME}") # If testing is turned off, this test is not okay if (NOT BUILD_REGRESSION_TESTS) set(BOOST_TEST_OKAY FALSE) endif(NOT BUILD_REGRESSION_TESTS) endmacro(boost_test_parse_args) # This macro attaches a the "known-failure" label to the given test # target if the build name matches any of the declared, known # failures. macro(boost_test_known_failures TEST) foreach(PATTERN ${ARGN}) if (${BUILDNAME} MATCHES ${PATTERN}) set_tests_properties("${PROJECT_NAME}-${TEST}" PROPERTIES LABELS "${PROJECT_NAME};known-failure") endif() endforeach() endmacro(boost_test_known_failures) # This macro creates a Boost regression test that will be executed. If # the test can be built, executed, and exits with a return code of # zero, it will be considered to have passed. # # boost_test_run(testname # [source1 source2 ...] # [ARGS arg1 arg2... ] # [COMPILE_FLAGS compileflags] # [LINK_FLAGS linkflags] # [LINK_LIBS linklibs] # [DEPENDS libdepend1 libdepend2 ...] # [EXTRA_OPTIONS option1 option2 ...]) # # testname is the name of the test. source1, source2, etc. are the # source files that will be built and linked into the test # executable. If no source files are provided, the file "testname.cpp" # will be used instead. # # There are several optional arguments to control how the regression # test is built and executed: # # ARGS: Provides additional arguments that will be passed to the # test executable when it is run. # # COMPILE_FLAGS: Provides additional compilation flags that will be # used when building this test. For example, one might want to add # "-DBOOST_SIGNALS_ASSERT=1" to turn on assertions within the library. # # LINK_FLAGS: Provides additional flags that will be passed to the # linker when linking the test excecutable. This option should not # be used to link in additional libraries; see LINK_LIBS and # DEPENDS. # # LINK_LIBS: Provides additional libraries against which the test # executable will be linked. For example, one might provide "expat" # as options to LINK_LIBS, to state that this executable should be # linked against the external "expat" library. Use LINK_LIBS for # libraries external to Boost; for Boost libraries, use DEPENDS. # # DEPENDS: States that this test executable depends on and links # against another Boost library. The argument to DEPENDS should be # the name of a particular variant of a Boost library, e.g., # boost_signals-static. # # EXTRA_OPTIONS: Provide extra options that will be passed on to # boost_add_executable. # # Example: # boost_test_run(signal_test DEPENDS boost_signals) macro(boost_test_run testname) boost_test_parse_args(${testname} ${ARGN} RUN) if (BOOST_TEST_OKAY) boost_add_executable(${testname} ${BOOST_TEST_SOURCES} OUTPUT_NAME tests/${PROJECT_NAME}/${testname} DEPENDS "${BOOST_TEST_DEPENDS}" LINK_LIBS ${BOOST_TEST_LINK_LIBS} LINK_FLAGS ${BOOST_TEST_LINK_FLAGS} COMPILE_FLAGS ${BOOST_TEST_COMPILE_FLAGS} NO_INSTALL ${BOOST_TEST_EXTRA_OPTIONS}) if (THIS_EXE_OKAY) get_target_property(THIS_TEST_OUTPUT_DIRECTORY ${testname} RUNTIME_OUTPUT_DIRECTORY) add_test (${BOOST_TEST_TESTNAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/tests/${PROJECT_NAME}/${testname} ${BOOST_TEST_ARGS}) set_tests_properties(${BOOST_TEST_TESTNAME} PROPERTIES LABELS "${PROJECT_NAME}" ) boost_test_known_failures(${testname} ${BOOST_TEST_KNOWN_FAILURES}) # Make sure that the -test target that corresponds to this # library or tool depends on this test executable. add_dependencies(${PROJECT_NAME}-test ${THIS_EXE_NAME}) if (BOOST_TEST_FAIL) set_tests_properties(${BOOST_TEST_TESTNAME} PROPERTIES WILL_FAIL ON) endif () endif(THIS_EXE_OKAY) endif (BOOST_TEST_OKAY) endmacro(boost_test_run) # # This macro creates a boost regression test that will be run but is # expected to fail (exit with nonzero return code). # See boost_test_run() # macro(boost_test_run_fail testname) boost_test_run(${testname} ${ARGN} FAIL) endmacro(boost_test_run_fail) # This macro creates a Boost regression test that will be compiled, # but not linked or executed. If the test can be compiled with no # failures, the test passes. # # boost_test_compile(testname # [source1] # [COMPILE_FLAGS compileflags]) # # testname is the name of the test. source1 is the name of the source # file that will be built. If no source file is provided, the file # "testname.cpp" will be used instead. # # The COMPILE_FLAGS argument provides additional arguments that will # be passed to the compiler when building this test. # Example: # boost_test_compile(advance) macro(boost_test_compile testname) boost_test_parse_args(${testname} ${ARGN} COMPILE) set (test_pass "PASSED") if (BOOST_TEST_FAIL) set (test_pass "FAILED") endif(BOOST_TEST_FAIL) if (BOOST_TEST_OKAY) # Determine the include directories to pass along to the underlying # project. # works but not great get_directory_property(BOOST_TEST_INCLUDE_DIRS INCLUDE_DIRECTORIES) set(BOOST_TEST_INCLUDES "") foreach(DIR ${BOOST_TEST_INCLUDE_DIRS}) set(BOOST_TEST_INCLUDES "${BOOST_TEST_INCLUDES};${DIR}") endforeach(DIR ${BOOST_TEST_INCLUDE_DIRS}) add_test(${BOOST_TEST_TESTNAME} ${CMAKE_CTEST_COMMAND} --build-and-test ${Boost_SOURCE_DIR}/tools/build/CMake/CompileTest ${Boost_BINARY_DIR}/tools/build/CMake/CompileTest --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-project CompileTest --build-options "-DSOURCE:STRING=${CMAKE_CURRENT_SOURCE_DIR}/${BOOST_TEST_SOURCES}" "-DINCLUDES:STRING=${BOOST_TEST_INCLUDES}" "-DCOMPILE_FLAGS:STRING=${BOOST_TEST_COMPILE_FLAGS}" ) set_tests_properties(${BOOST_TEST_TESTNAME} PROPERTIES LABELS "${PROJECT_NAME}" ) boost_test_known_failures(${testname} ${BOOST_TEST_KNOWN_FAILURES}) if (BOOST_TEST_FAIL) set_tests_properties(${BOOST_TEST_TESTNAME} PROPERTIES WILL_FAIL ON) endif () endif(BOOST_TEST_OKAY) endmacro(boost_test_compile) # # This macro creates a Boost regression test that is expected to # *fail* to compile. See boost_test_compile() # macro(boost_test_compile_fail testname) boost_test_compile(${testname} ${ARGN} FAIL) endmacro(boost_test_compile_fail) # # boost_test_link: # # # Each library "exports" itself to # ${CMAKE_BINARY_DIR}/exports/.cmake # # The list of 'depends' for these libraries has to match one of those # files, this way the export mechanism works. The generated # cmakelists will include() those exported .cmake files, for each # DEPENDS. # # macro(boost_test_link testname) boost_test_parse_args(${testname} ${ARGN} LINK) if(BOOST_TEST_OKAY) # Determine the include directories to pass along to the underlying # project. # works but not great get_directory_property(BOOST_TEST_INCLUDE_DIRS INCLUDE_DIRECTORIES) set(BOOST_TEST_INCLUDES "") foreach(DIR ${BOOST_TEST_INCLUDE_DIRS}) set(BOOST_TEST_INCLUDES "${BOOST_TEST_INCLUDES};${DIR}") endforeach(DIR ${BOOST_TEST_INCLUDE_DIRS}) add_test(${BOOST_TEST_TESTNAME} ${CMAKE_CTEST_COMMAND} -VV --build-and-test ${Boost_SOURCE_DIR}/tools/build/CMake/LinkTest ${Boost_BINARY_DIR}/tools/build/CMake/LinkTest --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-project LinkTest --build-options "-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}" "-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}" "-DBOOST_EXPORTS_DIR:FILEPATH=${CMAKE_BINARY_DIR}/exports" "-DSOURCE:STRING=${CMAKE_CURRENT_SOURCE_DIR}/${BOOST_TEST_SOURCES}" "-DINCLUDES:STRING=${BOOST_TEST_INCLUDES}" "-DCOMPILE_FLAGS:STRING=${BOOST_TEST_COMPILE_FLAGS}" "-DLINK_LIBS:STRING=${BOOST_TEST_LINK_LIBS}" "-DDEPENDS:STRING=${BOOST_TEST_DEPENDS}" ) set_tests_properties(${BOOST_TEST_TESTNAME} PROPERTIES LABELS "${PROJECT_NAME}" ) boost_test_known_failures(${testname} ${BOOST_TEST_KNOWN_FAILURES}) if (BOOST_TEST_FAIL) set_tests_properties(${BOOST_TEST_TESTNAME} PROPERTIES WILL_FAIL ON) endif () endif(BOOST_TEST_OKAY) endmacro(boost_test_link)