Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

catch_discover_test PROPERTIES does not work with lists #2424

Open
mxmlnkn opened this issue May 16, 2022 · 2 comments
Open

catch_discover_test PROPERTIES does not work with lists #2424

mxmlnkn opened this issue May 16, 2022 · 2 comments

Comments

@mxmlnkn
Copy link

mxmlnkn commented May 16, 2022

Describe the bug

When still using ParseAndAddCatchTests, I had code like this to set multiple environment variables for running the tests:

list(APPEND _environment_vars foo=bar)
list(APPEND _environment_vars f00=b4r)
ParseAndAddCatchTests(${test})
get_target_property(sub_tests ${test} ParseAndAddCatchTests_TESTS)
set_tests_properties(${sub_tests} PROPERTIES ENVIRONMENT "${_environment_vars}")

When using catch_discover_tests, I tried to replace the last three lines with:

catch_discover_tests(${test} PROPERTIES ENVIRONMENT "${_environment_vars_list}")

But after observing some indirect errors a while later, I noticed that only the very first environment variable was actually exported.

Looking under the hood, the problem seems to be that PROPERTIES are stored as a list itself, so that lists as value / semicolons in values will lead to problems.

My workaround currently is to add ENVIRONMENT; for each environment variable, resulting in:

string(REPLACE ";" ";ENVIRONMENT;" _environment_vars_list "${_environment_vars}")
catch_discover_tests(${test} PROPERTIES ENVIRONMENT "${_environment_vars_list}")

Expected behavior

catch_discover_tests(${test} PROPERTIES ENVIRONMENT "${_environment_vars_list}") should work even if there are multiple environment variables specified. This interface would be consistent with set_tests_properties.

Alternatively, this differing behavior for PROPERTIES should be documented, e.g., inside docs/cmake-integration.md, if possible with a suggested workaround.

Platform information:

  • Catch version: v2.13.9
@ferdnyc
Copy link
Contributor

ferdnyc commented Jun 17, 2022

@mxmlnkn

Looking under the hood, the problem seems to be that PROPERTIES are stored as a list itself, so that lists as value / semicolons in values will lead to problems.

Yeah, the bigger "problem" (meaning, barrier to using an environment list the way you'd like, which I agree is a reasonable expectation) is that catch_discover_tests just generates a big add_custom_command() call, as a post-build target attached to the testrunner, which re-invokes ${CMAKE_COMMAND} to execute a different Catch script with a bunch of variables defined. One of them is TEST_PROPERTIES, which is set to the list of arguments you provide to PROPERTIES in the call to catch_discover_tests():

Catch2/extras/Catch.cmake

Lines 149 to 159 in 165647a

add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"

Then, through a whole series of events, that argument gets transformed into a set_tests_properties() call for the test in question. It actually doesn't even process the arguments as pairs, it just splits out every argument and tacks it on to the end of the call. That, then, looks something like this:

set_tests_properties( [==[Test name]==] PROPERTIES WORKING_DIRECTORY /path/to/it 
LABELS Labels ENVIRONMENT [==[VAR=value]==])

Each separate PROPERTIES arg gets wrapped as a bracket argument if it contains any special chars. (As all of the ENVIRONMENT args always will, even when not trying to pass a list, since = is a special char.) So if you pass a semicolon-separated list to ENVIRONMENT, it invariably gets exploded along the way and you end up with something like,

set_tests_properties( [==[Test name]==] PROPERTIES WORKING_DIRECTORY /path/to/it 
LABELS Labels ENVIRONMENT [==[VAR1=val1]==] [==[VAR2=val2]==] [==[VAR3=val3]==])

I'm actually a bit surprised to learn (as you claim) that a call (effectively) like this, works:

catch_discover_tests(...
  PROPERTIES
    ENVIRONMENT VAR1=val1
    ENVIRONMENT VAR2=val2
)

Since that's going to end up transformed into this:

set_tests_properties( [==[Test name]==] PROPERTIES WORKING_DIRECTORY /path/to/it 
LABELS Labels ENVIRONMENT [==[VAR1=val1]==] ENVIRONMENT [==[VAR2=val2]==] 
ENVIRONMENT [==[VAR3=val3]==])

...and, while ENVIRONMENT is documented (by CMake) as taking a list of properties, it's not documented as auto-list-concatenating multiple values set on it separately, and Catch2 isn't using APPEND. (But I'm now beginning to suspect that all of the set_foo_properties() commands behave that way as a convenience. It would make sense, as APPEND is only for use in set_property() (singular).)

...Aaaanyway, point is, threading a "nested" list through the eye of that needle would be quite the undertaking. But at the very least, I agree, the restriction should be documented.

@mheimlich
Copy link
Contributor

As this does not work for lists of lists e.g. PATH, I created the pull request #2467.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants