1set(libs
2    ${mbedtls_target}
3    ${CMAKE_THREAD_LIBS_INIT}
4)
5
6# Set the project root directory if it's not already defined, as may happen if
7# the tests folder is included directly by a parent project, without including
8# the top level CMakeLists.txt.
9if(NOT DEFINED MBEDTLS_DIR)
10    set(MBEDTLS_DIR ${CMAKE_SOURCE_DIR})
11endif()
12
13if(NOT MBEDTLS_PYTHON_EXECUTABLE)
14    message(FATAL_ERROR "Cannot build test suites without Python 3")
15endif()
16
17# generated .data files will go there
18file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/suites)
19
20# Get base names for generated files
21execute_process(
22    COMMAND
23        ${MBEDTLS_PYTHON_EXECUTABLE}
24        ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_bignum_tests.py
25        --list-for-cmake
26    WORKING_DIRECTORY
27        ${CMAKE_CURRENT_SOURCE_DIR}/..
28    OUTPUT_VARIABLE
29        base_bignum_generated_data_files)
30string(REGEX REPLACE "[^;]*/" ""
31       base_bignum_generated_data_files "${base_bignum_generated_data_files}")
32
33execute_process(
34    COMMAND
35        ${MBEDTLS_PYTHON_EXECUTABLE}
36        ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_ecp_tests.py
37        --list-for-cmake
38    WORKING_DIRECTORY
39        ${CMAKE_CURRENT_SOURCE_DIR}/..
40    OUTPUT_VARIABLE
41        base_ecp_generated_data_files)
42string(REGEX REPLACE "[^;]*/" ""
43       base_ecp_generated_data_files "${base_ecp_generated_data_files}")
44
45execute_process(
46    COMMAND
47        ${MBEDTLS_PYTHON_EXECUTABLE}
48        ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
49        --list-for-cmake
50    WORKING_DIRECTORY
51        ${CMAKE_CURRENT_SOURCE_DIR}/..
52    OUTPUT_VARIABLE
53        base_psa_generated_data_files)
54string(REGEX REPLACE "[^;]*/" ""
55       base_psa_generated_data_files "${base_psa_generated_data_files}")
56
57# Derive generated file paths in the build directory. The generated data
58# files go into the suites/ subdirectory.
59set(base_generated_data_files
60    ${base_bignum_generated_data_files} ${base_ecp_generated_data_files} ${base_psa_generated_data_files})
61string(REGEX REPLACE "([^;]+)" "suites/\\1"
62       all_generated_data_files "${base_generated_data_files}")
63set(bignum_generated_data_files "")
64set(ecp_generated_data_files "")
65set(psa_generated_data_files "")
66foreach(file ${base_bignum_generated_data_files})
67    list(APPEND bignum_generated_data_files ${CMAKE_CURRENT_BINARY_DIR}/suites/${file})
68endforeach()
69foreach(file ${base_ecp_generated_data_files})
70    list(APPEND ecp_generated_data_files ${CMAKE_CURRENT_BINARY_DIR}/suites/${file})
71endforeach()
72foreach(file ${base_psa_generated_data_files})
73    list(APPEND psa_generated_data_files ${CMAKE_CURRENT_BINARY_DIR}/suites/${file})
74endforeach()
75
76if(GEN_FILES)
77    add_custom_command(
78        OUTPUT
79            ${bignum_generated_data_files}
80        WORKING_DIRECTORY
81            ${CMAKE_CURRENT_SOURCE_DIR}/..
82        COMMAND
83            ${MBEDTLS_PYTHON_EXECUTABLE}
84            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_bignum_tests.py
85            --directory ${CMAKE_CURRENT_BINARY_DIR}/suites
86        DEPENDS
87            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_bignum_tests.py
88            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_common.py
89            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_core.py
90            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_mod_raw.py
91            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_mod.py
92            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_case.py
93            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_data_generation.py
94    )
95    add_custom_command(
96        OUTPUT
97            ${ecp_generated_data_files}
98        WORKING_DIRECTORY
99            ${CMAKE_CURRENT_SOURCE_DIR}/..
100        COMMAND
101            ${MBEDTLS_PYTHON_EXECUTABLE}
102            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_ecp_tests.py
103            --directory ${CMAKE_CURRENT_BINARY_DIR}/suites
104        DEPENDS
105            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_ecp_tests.py
106            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_common.py
107            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/ecp.py
108            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_case.py
109            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_data_generation.py
110    )
111    add_custom_command(
112        OUTPUT
113            ${psa_generated_data_files}
114        WORKING_DIRECTORY
115            ${CMAKE_CURRENT_SOURCE_DIR}/..
116        COMMAND
117            ${MBEDTLS_PYTHON_EXECUTABLE}
118            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
119            --directory ${CMAKE_CURRENT_BINARY_DIR}/suites
120        DEPENDS
121            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
122            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/crypto_data_tests.py
123            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/crypto_knowledge.py
124            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/macro_collector.py
125            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/psa_information.py
126            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/psa_storage.py
127            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_case.py
128            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_data_generation.py
129            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_config.h
130            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_values.h
131            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_extra.h
132    )
133
134else()
135    foreach(file ${all_generated_data_files})
136        link_to_source(${file})
137    endforeach()
138endif()
139# CMake generates sub-makefiles for each target and calls them in subprocesses.
140# Without this command, cmake will generate rules in each sub-makefile. As a result,
141# they can cause race conditions in parallel builds.
142# With this line, only 4 sub-makefiles include the above command, that reduces
143# the risk of a race.
144add_custom_target(test_suite_bignum_generated_data DEPENDS ${bignum_generated_data_files})
145add_custom_target(test_suite_ecp_generated_data DEPENDS ${ecp_generated_data_files})
146add_custom_target(test_suite_psa_generated_data DEPENDS ${psa_generated_data_files})
147# If SKIP_TEST_SUITES is not defined with -D, get it from the environment.
148if((NOT DEFINED SKIP_TEST_SUITES) AND (DEFINED ENV{SKIP_TEST_SUITES}))
149    set(SKIP_TEST_SUITES $ENV{SKIP_TEST_SUITES})
150endif()
151# Test suites caught by SKIP_TEST_SUITES are built but not executed.
152# "foo" as a skip pattern skips "test_suite_foo" and "test_suite_foo.bar"
153# but not "test_suite_foobar".
154string(REGEX REPLACE "[ ,;]" "|" SKIP_TEST_SUITES_REGEX "${SKIP_TEST_SUITES}")
155string(REPLACE "." "\\." SKIP_TEST_SUITES_REGEX "${SKIP_TEST_SUITES_REGEX}")
156set(SKIP_TEST_SUITES_REGEX "^(${SKIP_TEST_SUITES_REGEX})(\$|\\.)")
157
158function(add_test_suite suite_name)
159    if(ARGV1)
160        set(data_name ${ARGV1})
161    else()
162        set(data_name ${suite_name})
163    endif()
164
165    # Get the test names of the tests with generated .data files
166    # from the generated_data_files list in parent scope.
167    set(bignum_generated_data_names "")
168    set(ecp_generated_data_names "")
169    set(psa_generated_data_names "")
170    foreach(generated_data_file ${bignum_generated_data_files})
171        # Get the plain filename
172        get_filename_component(generated_data_name ${generated_data_file} NAME)
173        # Remove the ".data" extension
174        get_name_without_last_ext(generated_data_name ${generated_data_name})
175        # Remove leading "test_suite_"
176        string(SUBSTRING ${generated_data_name} 11 -1 generated_data_name)
177        list(APPEND bignum_generated_data_names ${generated_data_name})
178    endforeach()
179    foreach(generated_data_file ${ecp_generated_data_files})
180        # Get the plain filename
181        get_filename_component(generated_data_name ${generated_data_file} NAME)
182        # Remove the ".data" extension
183        get_name_without_last_ext(generated_data_name ${generated_data_name})
184        # Remove leading "test_suite_"
185        string(SUBSTRING ${generated_data_name} 11 -1 generated_data_name)
186        list(APPEND ecp_generated_data_names ${generated_data_name})
187    endforeach()
188    foreach(generated_data_file ${psa_generated_data_files})
189        # Get the plain filename
190        get_filename_component(generated_data_name ${generated_data_file} NAME)
191        # Remove the ".data" extension
192        get_name_without_last_ext(generated_data_name ${generated_data_name})
193        # Remove leading "test_suite_"
194        string(SUBSTRING ${generated_data_name} 11 -1 generated_data_name)
195        list(APPEND psa_generated_data_names ${generated_data_name})
196    endforeach()
197
198    if(";${bignum_generated_data_names};" MATCHES ";${data_name};")
199        set(data_file
200            ${CMAKE_CURRENT_BINARY_DIR}/suites/test_suite_${data_name}.data)
201        set(dependency test_suite_bignum_generated_data)
202    elseif(";${ecp_generated_data_names};" MATCHES ";${data_name};")
203        set(data_file
204            ${CMAKE_CURRENT_BINARY_DIR}/suites/test_suite_${data_name}.data)
205        set(dependency test_suite_ecp_generated_data)
206    elseif(";${psa_generated_data_names};" MATCHES ";${data_name};")
207        set(data_file
208            ${CMAKE_CURRENT_BINARY_DIR}/suites/test_suite_${data_name}.data)
209        set(dependency test_suite_psa_generated_data)
210    else()
211        set(data_file
212            ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${data_name}.data)
213        set(dependency test_suite_bignum_generated_data test_suite_ecp_generated_data test_suite_psa_generated_data)
214    endif()
215
216    add_custom_command(
217        OUTPUT
218            # The output filename of generate_test_code.py is derived from the -d
219            # input argument.
220            test_suite_${data_name}.c
221        COMMAND
222            ${MBEDTLS_PYTHON_EXECUTABLE}
223            ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_test_code.py
224            -f ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${suite_name}.function
225            -d ${data_file}
226            -t ${CMAKE_CURRENT_SOURCE_DIR}/suites/main_test.function
227            -p ${CMAKE_CURRENT_SOURCE_DIR}/suites/host_test.function
228            -s ${CMAKE_CURRENT_SOURCE_DIR}/suites
229            --helpers-file ${CMAKE_CURRENT_SOURCE_DIR}/suites/helpers.function
230            -o .
231        DEPENDS
232            ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_test_code.py
233            ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${suite_name}.function
234            ${data_file}
235            ${CMAKE_CURRENT_SOURCE_DIR}/suites/main_test.function
236            ${CMAKE_CURRENT_SOURCE_DIR}/suites/host_test.function
237            ${CMAKE_CURRENT_SOURCE_DIR}/suites/helpers.function
238            ${mbedtls_target}
239        BYPRODUCTS
240            test_suite_${data_name}.datax
241    )
242
243    add_executable(test_suite_${data_name} test_suite_${data_name}.c
244                   $<TARGET_OBJECTS:mbedtls_test>
245                   $<TARGET_OBJECTS:mbedtls_test_helpers>)
246    add_dependencies(test_suite_${data_name} ${dependency})
247    target_link_libraries(test_suite_${data_name} ${libs})
248    # Include test-specific header files from ./include and private header
249    # files (used by some invasive tests) from ../library. Public header
250    # files are automatically included because the library targets declare
251    # them as PUBLIC.
252    target_include_directories(test_suite_${data_name}
253        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
254        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../library)
255    # Request C11, which is needed for memory poisoning tests
256    set_target_properties(test_suite_${data_name} PROPERTIES C_STANDARD 11)
257
258    if(${data_name} MATCHES ${SKIP_TEST_SUITES_REGEX})
259        message(STATUS "The test suite ${data_name} will not be executed.")
260    else()
261        add_test(${data_name}-suite test_suite_${data_name} --verbose)
262    endif()
263endfunction(add_test_suite)
264
265# Enable definition of various functions used throughout the testsuite
266# (gethostname, strdup, fileno...) even when compiling with -std=c99. Harmless
267# on non-POSIX platforms.
268add_definitions("-D_POSIX_C_SOURCE=200809L")
269
270if(CMAKE_COMPILER_IS_CLANG)
271    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wdocumentation -Wno-documentation-deprecated-sync -Wunreachable-code")
272endif(CMAKE_COMPILER_IS_CLANG)
273
274if(MSVC)
275    # If a warning level has been defined, suppress all warnings for test code
276    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W0")
277    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX-")
278endif(MSVC)
279
280file(GLOB test_suites RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" suites/*.data)
281list(APPEND test_suites ${all_generated_data_files})
282# If the generated .data files are present in the source tree, we just added
283# them twice, both through GLOB and through ${all_generated_data_files}.
284list(REMOVE_DUPLICATES test_suites)
285list(SORT test_suites)
286foreach(test_suite ${test_suites})
287    get_filename_component(data_name ${test_suite} NAME)
288    string(REGEX REPLACE "\\.data\$" "" data_name "${data_name}")
289    string(REPLACE "test_suite_" "" data_name "${data_name}")
290    string(REGEX MATCH "[^.]*" function_name "${data_name}")
291    add_test_suite(${function_name} ${data_name})
292endforeach(test_suite)
293
294# Make scripts and data files needed for testing available in an
295# out-of-source build.
296if (NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
297    if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/seedfile")
298        link_to_source(seedfile)
299    endif()
300    link_to_source(Descriptions.txt)
301    link_to_source(compat.sh)
302    link_to_source(context-info.sh)
303    link_to_source(data_files)
304    link_to_source(scripts)
305    link_to_source(ssl-opt.sh)
306    link_to_source(opt-testcases)
307endif()
308