Skip to content

Commit 21911e1

Browse files
A way to register additional test targets and support .py only tests. (#3590)
* A way to register additional test targets. * Support specifying tests with extension. * Ensure TEST_OVERRIDE is backwards compatible. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Ensure regex is non greedy. Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent d434b5f commit 21911e1

File tree

2 files changed

+113
-66
lines changed

2 files changed

+113
-66
lines changed

.github/CONTRIBUTING.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,9 @@ tests with these targets:
159159
* `test_cmake_build`: Install / subdirectory tests
160160

161161
If you want to build just a subset of tests, use
162-
`-DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp"`. If this is
163-
empty, all tests will be built.
162+
`-DPYBIND11_TEST_OVERRIDE="test_callbacks;test_pickling"`. If this is
163+
empty, all tests will be built. Tests are specified without an extension if they need both a .py and
164+
.cpp file.
164165

165166
You may also pass flags to the `pytest` target by editing `tests/pytest.ini` or
166167
by using the `PYTEST_ADDOPTS` environment variable

tests/CMakeLists.txt

Lines changed: 110 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,25 @@ endif()
1919
# Only needed for CMake < 3.5 support
2020
include(CMakeParseArguments)
2121

22-
# Filter out items; print an optional message if any items filtered
22+
# Filter out items; print an optional message if any items filtered. This ignores extensions.
2323
#
2424
# Usage:
2525
# pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "")
2626
#
2727
macro(pybind11_filter_tests LISTNAME)
2828
cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN})
2929
set(PYBIND11_FILTER_TESTS_FOUND OFF)
30+
# Make a list of the test without any extensions, for easier filtering.
31+
set(_TMP_ACTUAL_LIST "${${LISTNAME}};") # enforce ';' at the end to allow matching last item.
32+
string(REGEX REPLACE "\\.[^.;]*;" ";" LIST_WITHOUT_EXTENSIONS "${_TMP_ACTUAL_LIST}")
3033
foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS)
31-
list(FIND ${LISTNAME} ${filename} _FILE_FOUND)
34+
string(REGEX REPLACE "\\.[^.]*$" "" filename_no_ext ${filename})
35+
# Search in the list without extensions.
36+
list(FIND LIST_WITHOUT_EXTENSIONS ${filename_no_ext} _FILE_FOUND)
3237
if(_FILE_FOUND GREATER -1)
33-
list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND})
38+
list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND}) # And remove from the list with extensions.
39+
list(REMOVE_AT LIST_WITHOUT_EXTENSIONS ${_FILE_FOUND}
40+
)# And our search list, to ensure it is in sync.
3441
set(PYBIND11_FILTER_TESTS_FOUND ON)
3542
endif()
3643
endforeach()
@@ -47,6 +54,18 @@ macro(possibly_uninitialized)
4754
endforeach()
4855
endmacro()
4956

57+
# Function to add additional targets if any of the provided tests are found.
58+
# Needles; Specifies the test names to look for.
59+
# Additions; Specifies the additional test targets to add when any of the needles are found.
60+
macro(tests_extra_targets needles additions)
61+
# Add the index for this relation to the index extra targets map.
62+
list(LENGTH PYBIND11_TEST_EXTRA_TARGETS PYBIND11_TEST_EXTRA_TARGETS_LEN)
63+
list(APPEND PYBIND11_TEST_EXTRA_TARGETS ${PYBIND11_TEST_EXTRA_TARGETS_LEN})
64+
# Add the test names to look for, and the associated test target additions.
65+
set(PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${needles})
66+
set(PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${additions})
67+
endmacro()
68+
5069
# New Python support
5170
if(DEFINED Python_EXECUTABLE)
5271
set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
@@ -92,55 +111,67 @@ if(PYBIND11_CUDA_TESTS)
92111
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
93112
endif()
94113

95-
# Full set of test files (you can override these; see below)
114+
# Full set of test files (you can override these; see below, overrides ignore extension)
115+
# Any test that has no extension is both .py and .cpp, so 'foo' will add 'foo.cpp' and 'foo.py'.
116+
# Any test that has an extension is exclusively that and handled as such.
96117
set(PYBIND11_TEST_FILES
97-
test_async.cpp
98-
test_buffers.cpp
99-
test_builtin_casters.cpp
100-
test_call_policies.cpp
101-
test_callbacks.cpp
102-
test_chrono.cpp
103-
test_class.cpp
104-
test_const_name.cpp
105-
test_constants_and_functions.cpp
106-
test_copy_move.cpp
107-
test_custom_type_casters.cpp
108-
test_custom_type_setup.cpp
109-
test_docstring_options.cpp
110-
test_eigen.cpp
111-
test_enum.cpp
112-
test_eval.cpp
113-
test_exceptions.cpp
114-
test_factory_constructors.cpp
115-
test_gil_scoped.cpp
116-
test_iostream.cpp
117-
test_kwargs_and_defaults.cpp
118-
test_local_bindings.cpp
119-
test_methods_and_attributes.cpp
120-
test_modules.cpp
121-
test_multiple_inheritance.cpp
122-
test_numpy_array.cpp
123-
test_numpy_dtypes.cpp
124-
test_numpy_vectorize.cpp
125-
test_opaque_types.cpp
126-
test_operator_overloading.cpp
127-
test_pickling.cpp
128-
test_pytypes.cpp
129-
test_sequences_and_iterators.cpp
130-
test_smart_ptr.cpp
131-
test_stl.cpp
132-
test_stl_binders.cpp
133-
test_tagbased_polymorphic.cpp
134-
test_thread.cpp
135-
test_union.cpp
136-
test_virtual_functions.cpp)
118+
test_async
119+
test_buffers
120+
test_builtin_casters
121+
test_call_policies
122+
test_callbacks
123+
test_chrono
124+
test_class
125+
test_const_name
126+
test_constants_and_functions
127+
test_copy_move
128+
test_custom_type_casters
129+
test_custom_type_setup
130+
test_docstring_options
131+
test_eigen
132+
test_enum
133+
test_eval
134+
test_exceptions
135+
test_factory_constructors
136+
test_gil_scoped
137+
test_iostream
138+
test_kwargs_and_defaults
139+
test_local_bindings
140+
test_methods_and_attributes
141+
test_modules
142+
test_multiple_inheritance
143+
test_numpy_array
144+
test_numpy_dtypes
145+
test_numpy_vectorize
146+
test_opaque_types
147+
test_operator_overloading
148+
test_pickling
149+
test_pytypes
150+
test_sequences_and_iterators
151+
test_smart_ptr
152+
test_stl
153+
test_stl_binders
154+
test_tagbased_polymorphic
155+
test_thread
156+
test_union
157+
test_virtual_functions)
137158

138159
# Invoking cmake with something like:
139160
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" ..
140161
# lets you override the tests that get compiled and run. You can restore to all tests with:
141162
# cmake -DPYBIND11_TEST_OVERRIDE= ..
142163
if(PYBIND11_TEST_OVERRIDE)
143-
set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})
164+
# Instead of doing a direct override here, we iterate over the overrides without extension and
165+
# match them against entries from the PYBIND11_TEST_FILES, anything that not matches goes into the filter list.
166+
string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_OVERRIDE_NO_EXT "${PYBIND11_TEST_OVERRIDE};")
167+
string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_FILES_NO_EXT "${PYBIND11_TEST_FILES};")
168+
# This allows the override to be done with extensions, preserving backwards compatibility.
169+
foreach(test_name ${TEST_FILES_NO_EXT})
170+
if(NOT ${test_name} IN_LIST TEST_OVERRIDE_NO_EXT
171+
)# If not in the whitelist, add to be filtered out.
172+
list(APPEND PYBIND11_TEST_FILTER ${test_name})
173+
endif()
174+
endforeach()
144175
endif()
145176

146177
# You can also filter tests:
@@ -162,15 +193,34 @@ if(PYBIND11_CUDA_TESTS)
162193
"Skipping test_constants_and_functions due to incompatible exception specifications")
163194
endif()
164195

165-
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
196+
# Now that the test filtering is complete, we need to split the list into the test for PYTEST
197+
# and the list for the cpp targets.
198+
set(PYBIND11_CPPTEST_FILES "")
199+
set(PYBIND11_PYTEST_FILES "")
200+
201+
foreach(test_name ${PYBIND11_TEST_FILES})
202+
if(test_name MATCHES "\\.py$") # Ends in .py, purely python test.
203+
list(APPEND PYBIND11_PYTEST_FILES ${test_name})
204+
elseif(test_name MATCHES "\\.cpp$") # Ends in .cpp, purely cpp test.
205+
list(APPEND PYBIND11_CPPTEST_FILES ${test_name})
206+
elseif(NOT test_name MATCHES "\\.") # No extension specified, assume both, add extension.
207+
list(APPEND PYBIND11_PYTEST_FILES ${test_name}.py)
208+
list(APPEND PYBIND11_CPPTEST_FILES ${test_name}.cpp)
209+
else()
210+
message(WARNING "Unhanded test extension in test: ${test_name}")
211+
endif()
212+
endforeach()
213+
set(PYBIND11_TEST_FILES ${PYBIND11_CPPTEST_FILES})
214+
list(SORT PYBIND11_PYTEST_FILES)
166215

167216
# Contains the set of test files that require pybind11_cross_module_tests to be
168217
# built; if none of these are built (i.e. because TEST_OVERRIDE is used and
169218
# doesn't include them) the second module doesn't get built.
170-
set(PYBIND11_CROSS_MODULE_TESTS test_exceptions.py test_local_bindings.py test_stl.py
171-
test_stl_binders.py)
219+
tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_stl_binders.py"
220+
"pybind11_cross_module_tests")
172221

173-
set(PYBIND11_CROSS_MODULE_GIL_TESTS test_gil_scoped.py)
222+
# And add additional targets for other tests.
223+
tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
174224

175225
set(PYBIND11_EIGEN_REPO
176226
"https://gitlab.com/libeigen/eigen.git"
@@ -353,21 +403,17 @@ endfunction()
353403

354404
set(test_targets pybind11_tests)
355405

356-
# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it
357-
foreach(t ${PYBIND11_CROSS_MODULE_TESTS})
358-
list(FIND PYBIND11_PYTEST_FILES ${t} i)
359-
if(i GREATER -1)
360-
list(APPEND test_targets pybind11_cross_module_tests)
361-
break()
362-
endif()
363-
endforeach()
364-
365-
foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})
366-
list(FIND PYBIND11_PYTEST_FILES ${t} i)
367-
if(i GREATER -1)
368-
list(APPEND test_targets cross_module_gil_utils)
369-
break()
370-
endif()
406+
# Check if any tests need extra targets by iterating through the mappings registered.
407+
foreach(i ${PYBIND11_TEST_EXTRA_TARGETS})
408+
foreach(needle ${PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${i}})
409+
if(needle IN_LIST PYBIND11_PYTEST_FILES)
410+
# Add all the additional targets to the test list. List join in newer cmake.
411+
foreach(extra_target ${PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${i}})
412+
list(APPEND test_targets ${extra_target})
413+
endforeach()
414+
break() # Breaks out of the needle search, continues with the next mapping.
415+
endif()
416+
endforeach()
371417
endforeach()
372418

373419
# Support CUDA testing by forcing the target file to compile with NVCC

0 commit comments

Comments
 (0)