1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
#
# Testing CamiTK python module (defined as ${PYCAMITK_LIB_NAME})
#
# Testing CamiTK python module is done in an automatically generated python environment (in directory VENV_DIR).
# Tests are written in the PYCAMITK_TEST_SCRIPT.
# All python packages required by the tests must be declared in TEST_REQUIREMENTS and are automatically
# installed in the virtual environment. They will all be labeled PYTEST_TARGET+test-name
#
# This is done in 3 steps:
# 1. use python to create a virtual env
# 2. use PYTEST_DISCOVER_TESTS_SCRIPT to generate CTEST_GENERATED_FILE, a CMake file that contains the list of ctests to add
# 3. include CTEST_GENERATED_FILE in the CMake current configuration
#
# PYTEST_DISCOVER_TESTS_SCRIPT read the PYCAMITK_TEST_SCRIPT using ast (abstract syntax tree) package to list all the
# function that start with "test_" (that is all the functions used by pytest to generate a test). It then add one ctest
# for each pytest.
#
# Note:
# - if you modify PYCAMITK_TEST_SCRIPT or PYTEST_DISCOVER_TESTS_SCRIPT, CMake will detect it automatically and reconfigure the project
# - if you modify TEST_REQUIREMENTS, CMake will detect it automatically and rerun pip install -r ${TEST_REQUIREMENTS}
#
# Warning:
# VENV_DIR, PYTHON_EXTRA_PATH and PYTEST_TARGET variables are required by the CTEST_GENERATED_FILE (see PYTEST_DISCOVER_TESTS_SCRIPT source):
# - VENV_DIR is used to determine the python to use (the venv should have pytest installed)
# - PYTHON_EXTRA_PATH is used to determine were the python module to be tested is found
# - PYTEST_TARGET is used to add a label in order for ctest/CI to associate the test to the given target
# Required variables
set(VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/.venv")
set(TEST_REQUIREMENTS "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt")
set(PYTEST_DISCOVER_TESTS_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/pytest_discover_tests.py")
set(PYTEST_TARGET "${PYCAMITK_TARGET_LIB_NAME}") # to associate the test with the target
set(PYTHON_EXTRA_PATH "${OUTPUT_DIRECTORY}") # where camik python module shared object is built
set(PYCAMITK_TEST_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/camitk_python_test.py")
set(CTEST_GENERATED_FILE "${CMAKE_CURRENT_BINARY_DIR}/generated_pytests.cmake")
if(WIN32)
set(VENV_EXECUTABLE_DIR "${VENV_DIR}/Scripts")
# On Windows, add ${CAMITK_BUILD_PRIVATE_LIB_DIR} and ${CAMITK_BUILD_BIN_DIR} to PATH in order
# to find the public and private library dll
if (MSVC)
# MSVC requires path to lib for the DLL
string(REGEX REPLACE "/" "\\\\" PATH_TO_DLL "${CAMITK_BUILD_PRIVATE_LIB_DIR};${CAMITK_BUILD_BIN_DIR}")
# all ; needs to be escaped as well...
# see https://developercommunity.visualstudio.com/t/cmake-tests-environment-variables-ignored/210188#T-N931342
string(REPLACE ";" "\\;" ESCAPED_PATH "$ENV{PATH};${PATH_TO_DLL}")
# file(TO_NATIVE_PATH "${PYTHON_EXTRA_PATH}" PYTHON_EXTRA_PATH)
string(REGEX REPLACE "/" "\\\\" PYTHON_EXTRA_PATH "${PYTHON_EXTRA_PATH}")
message(STATUS "On windows: PYTHON_EXTRA_PATH=${PYTHON_EXTRA_PATH}")
endif()
else()
set(VENV_EXECUTABLE_DIR "${VENV_DIR}/bin")
unset(ESCAPED_PATH)
endif()
#
# 1. create python virtual environment for testing
#
if (NOT EXISTS ${VENV_DIR})
message(STATUS "Creating python virtual environment for CamiTK python module tests using python '${Python_EXECUTABLE}' in directory ${VENV_DIR}...")
execute_process(COMMAND "${Python_EXECUTABLE}" "-m" "venv" "${VENV_DIR}"
RESULT_VARIABLE PYTHON_CREATE_VENV_RETURN_CODE
OUTPUT_VARIABLE PYTHON_CREATE_VENV_OUTPUT
ERROR_VARIABLE PYTHON_CREATE_VENV_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE)
if(PYTHON_CREATE_VENV_RETURN_CODE)
message(FATAL_ERROR "Failed to create python virtual environment:\nreturn code:\n${PYTHON_CREATE_VENV_RETURN_CODE}\noutput:\n${PYTHON_CREATE_VENV_OUTPUT}")
else()
message(STATUS "Python virtual environment for CamiTK python module tests created in ${VENV_DIR}")
endif()
message(STATUS "Installing CamiTK python module tests requirements...")
execute_process(COMMAND "${VENV_EXECUTABLE_DIR}/pip" "install" "-r" "${TEST_REQUIREMENTS}"
WORKING_DIRECTORY ${VENV_DIR}
RESULT_VARIABLE PYTHON_INSTALL_REQUIREMENTS_RETURN_CODE
OUTPUT_VARIABLE PYTHON_INSTALL_REQUIREMENTS_OUTPUT
ERROR_VARIABLE PYTHON_INSTALL_REQUIREMENTS_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE)
if(PYTHON_INSTALL_REQUIREMENTS_RETURN_CODE)
message(FATAL_ERROR "Failed to install requirements for CamiTK python module tests:\nreturn code:\n${PYTHON_INSTALL_REQUIREMENTS_RETURN_CODE}\noutput:\n${PYTHON_INSTALL_REQUIREMENTS_OUTPUT}")
else()
message(STATUS "Python virtual environment for CamiTK python module tests ready.")
endif()
endif()
# reinstall dependencies if requirements.txt changes
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/requirements-last-updated.txt
COMMAND "${VENV_EXECUTABLE_DIR}/pip" "install" "-r" "${TEST_REQUIREMENTS}"
COMMAND ${CMAKE_COMMAND} -E echo "Pip install executed" > ${CMAKE_CURRENT_BINARY_DIR}/requirements-last-updated.txt
DEPENDS ${TEST_REQUIREMENTS}
COMMENT "Updating CamiTK python module test dependencies because ${TEST_REQUIREMENTS} has changed"
VERBATIM
)
add_custom_target(
${PYCAMITK_TARGET_LIB_NAME}-test-requirements ALL
COMMENT "Update CamiTK python module test requirements when necessary"
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/requirements-last-updated.txt
)
#
# 2. Create the list of tests from PYCAMITK_TEST_FILE (at configure time)
#
execute_process(COMMAND "${VENV_EXECUTABLE_DIR}/python" ${PYTEST_DISCOVER_TESTS_SCRIPT} ${PYCAMITK_TEST_SCRIPT} "${CTEST_GENERATED_FILE}" "${PYTHON_EXTRA_PATH}" "${ESCAPED_PATH}"
WORKING_DIRECTORY ${VENV_DIR}
RESULT_VARIABLE PYTHON_GENERATE_TESTS_RETURN_CODE
OUTPUT_VARIABLE PYTHON_GENERATE_TESTS_OUTPUT
ERROR_VARIABLE PYTHON_GENERATE_TESTS_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE)
if(PYTHON_GENERATE_TESTS_RETURN_CODE)
message(FATAL_ERROR "Failed to generate tests from pytest:\nreturn code:\n${PYTHON_GENERATE_TESTS_RETURN_CODE}\noutput:\n${PYTHON_GENERATE_TESTS_OUTPUT}")
else()
message(STATUS "Python test generated from pytest using PYTHON_EXTRA_PATH=${PYTHON_EXTRA_PATH}.")
endif()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${PYTEST_DISCOVER_TESTS_SCRIPT}"
"${PYCAMITK_TEST_SCRIPT}"
)
#
# 3. Include the generated tests
#
include("${CTEST_GENERATED_FILE}")
|