From e791ffac61912f6540742aabaf4cb78a4d475a16 Mon Sep 17 00:00:00 2001 From: Sergey Bobrenok Date: Wed, 15 May 2019 22:10:39 +0700 Subject: add_test: Add COMMAND_EXPAND_LISTS option Add a `COMMAND_EXPAND_LISTS` option to the `add_test` command to cause `;`-separated lists produced by generator expressions to be expanded into multiple arguments. The `add_custom_command` command already has such an option. Fixes: #17284 --- Help/command/add_test.rst | 8 ++++- Help/release/dev/add_test-expand_lists.rst | 6 ++++ Source/cmAddTestCommand.cxx | 9 ++++++ Source/cmTest.cxx | 13 +++++++- Source/cmTest.h | 5 +++ Source/cmTestGenerator.cxx | 37 +++++++++++++++++----- Source/cmTestGenerator.h | 4 +++ Tests/RunCMake/CMakeLists.txt | 2 ++ .../CTestCommandExpandLists/CMakeLists.txt | 3 ++ .../CTestCommandExpandLists/CMakeLists.txt.in | 3 ++ .../CTestCommandExpandLists/RunCMakeTest.cmake | 5 +++ .../CTestCommandExpandLists/compare_options.cmake | 14 ++++++++ .../expandEmptyCommand-result.txt | 1 + .../expandEmptyCommand-stderr.txt | 1 + .../expandEmptyCommand-stdout.txt | 13 ++++++++ .../expandEmptyCommand.cmake | 10 ++++++ .../expandGeneratorExpressionResult-result.txt | 1 + .../expandGeneratorExpressionResult-stdout.txt | 7 ++++ .../expandGeneratorExpressionResult.cmake | 19 +++++++++++ .../multipleExpandOptions-result.txt | 1 + .../multipleExpandOptions-stderr.txt | 2 ++ .../multipleExpandOptions-stdout.txt | 2 ++ .../multipleExpandOptions.cmake | 8 +++++ .../RunCMake/CTestCommandExpandLists/test.cmake.in | 15 +++++++++ 24 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 Help/release/dev/add_test-expand_lists.rst create mode 100644 Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in create mode 100644 Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake create mode 100644 Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake create mode 100644 Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake create mode 100644 Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt create mode 100644 Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake create mode 100644 Tests/RunCMake/CTestCommandExpandLists/test.cmake.in diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst index 46b9b63..884b2ee 100644 --- a/Help/command/add_test.rst +++ b/Help/command/add_test.rst @@ -7,7 +7,8 @@ Add a test to the project to be run by :manual:`ctest(1)`. add_test(NAME COMMAND [...] [CONFIGURATIONS ...] - [WORKING_DIRECTORY ]) + [WORKING_DIRECTORY ] + [COMMAND_EXPAND_LISTS]) Adds a test called ````. The test name may not contain spaces, quotes, or other characters special in CMake syntax. The options are: @@ -28,6 +29,11 @@ quotes, or other characters special in CMake syntax. The options are: directory set to the build directory corresponding to the current source directory. +``COMMAND_EXPAND_LISTS`` + Lists in ``COMMAND`` arguments will be expanded, including those + created with + :manual:`generator expressions `. + The given test command is expected to exit with code ``0`` to pass and non-zero to fail, or vice-versa if the :prop_test:`WILL_FAIL` test property is set. Any output written to stdout or stderr will be diff --git a/Help/release/dev/add_test-expand_lists.rst b/Help/release/dev/add_test-expand_lists.rst new file mode 100644 index 0000000..88d26b7 --- /dev/null +++ b/Help/release/dev/add_test-expand_lists.rst @@ -0,0 +1,6 @@ +add_test-expand_lists +--------------------- + +* The command :command:`add_test` learned the option ``COMMAND_EXPAND_LISTS`` + which causes lists in the ``COMMAND`` argument to be expanded, including + lists created by generator expressions. diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx index bf28702..b0c462b 100644 --- a/Source/cmAddTestCommand.cxx +++ b/Source/cmAddTestCommand.cxx @@ -58,6 +58,7 @@ bool cmAddTestCommand::HandleNameMode(std::vector const& args) std::vector configurations; std::string working_directory; std::vector command; + bool command_expand_lists = false; // Read the arguments. enum Doing @@ -88,6 +89,13 @@ bool cmAddTestCommand::HandleNameMode(std::vector const& args) return false; } doing = DoingWorkingDirectory; + } else if (args[i] == "COMMAND_EXPAND_LISTS") { + if (command_expand_lists) { + this->SetError(" may be given at most one COMMAND_EXPAND_LISTS."); + return false; + } + command_expand_lists = true; + doing = DoingNone; } else if (doing == DoingName) { name = args[i]; doing = DoingNone; @@ -134,6 +142,7 @@ bool cmAddTestCommand::HandleNameMode(std::vector const& args) if (!working_directory.empty()) { test->SetProperty("WORKING_DIRECTORY", working_directory.c_str()); } + test->SetCommandExpandLists(command_expand_lists); this->Makefile->AddTestGenerator(new cmTestGenerator(test, configurations)); return true; diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index 7d45cf5..01f2b96 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -8,7 +8,8 @@ #include "cmSystemTools.h" cmTest::cmTest(cmMakefile* mf) - : Backtrace(mf->GetBacktrace()) + : CommandExpandLists(false) + , Backtrace(mf->GetBacktrace()) { this->Makefile = mf; this->OldStyle = true; @@ -59,3 +60,13 @@ void cmTest::AppendProperty(const std::string& prop, const char* value, { this->Properties.AppendProperty(prop, value, asString); } + +bool cmTest::GetCommandExpandLists() const +{ + return this->CommandExpandLists; +} + +void cmTest::SetCommandExpandLists(bool b) +{ + this->CommandExpandLists = b; +} diff --git a/Source/cmTest.h b/Source/cmTest.h index 88dc730..02d8f46 100644 --- a/Source/cmTest.h +++ b/Source/cmTest.h @@ -51,10 +51,15 @@ public: bool GetOldStyle() const { return this->OldStyle; } void SetOldStyle(bool b) { this->OldStyle = b; } + /** Set/Get whether lists in command lines should be expanded. */ + bool GetCommandExpandLists() const; + void SetCommandExpandLists(bool b); + private: cmPropertyMap Properties; std::string Name; std::vector Command; + bool CommandExpandLists; bool OldStyle; diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 571cd09..ce960dc 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -76,12 +76,22 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, // Start the test command. os << indent << "add_test(" << this->Test->GetName() << " "; - // Get the test command line to be executed. - std::vector const& command = this->Test->GetCommand(); + // Evaluate command line arguments + std::vector argv = + EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config); + + // Expand arguments if COMMAND_EXPAND_LISTS is set + if (this->Test->GetCommandExpandLists()) { + argv = cmSystemTools::ExpandedLists(argv.begin(), argv.end()); + // Expanding lists on an empty command may have left it empty + if (argv.empty()) { + argv.emplace_back(); + } + } // Check whether the command executable is a target whose name is to // be translated. - std::string exe = command[0]; + std::string exe = argv[0]; cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(exe); if (target && target->GetType() == cmStateEnums::EXECUTABLE) { // Use the target file on disk. @@ -101,16 +111,14 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, } } else { // Use the command name given. - exe = ge.Parse(exe)->Evaluate(this->LG, config); cmSystemTools::ConvertToUnixSlashes(exe); } // Generate the command line with full escapes. os << cmOutputConverter::EscapeForCMake(exe); - for (std::string const& arg : cmMakeRange(command).advance(1)) { - os << " " - << cmOutputConverter::EscapeForCMake( - ge.Parse(arg)->Evaluate(this->LG, config)); + + for (auto const& arg : cmMakeRange(argv).advance(1)) { + os << " " << cmOutputConverter::EscapeForCMake(arg); } // Finish the test command. @@ -208,3 +216,16 @@ void cmTestGenerator::GenerateInternalProperties(std::ostream& os) os << "\""; } + +std::vector cmTestGenerator::EvaluateCommandLineArguments( + const std::vector& argv, cmGeneratorExpression& ge, + const std::string& config) const +{ + // Evaluate executable name and arguments + auto evaluatedRange = + cmMakeRange(argv).transform([&](const std::string& arg) { + return ge.Parse(arg)->Evaluate(this->LG, config); + }); + + return { evaluatedRange.begin(), evaluatedRange.end() }; +} diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h index 8b9cf78..7ac68eb 100644 --- a/Source/cmTestGenerator.h +++ b/Source/cmTestGenerator.h @@ -11,6 +11,7 @@ #include #include +class cmGeneratorExpression; class cmLocalGenerator; class cmTest; @@ -38,6 +39,9 @@ public: private: void GenerateInternalProperties(std::ostream& os); + std::vector EvaluateCommandLineArguments( + const std::vector& argv, cmGeneratorExpression& ge, + const std::string& config) const; protected: void GenerateScriptConfigs(std::ostream& os, Indent indent) override; diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 69f8162..9a9d543 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -565,3 +565,5 @@ if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|9[0-9])") add_RunCMake_test(CSharpCustomCommand) add_RunCMake_test(CSharpReferenceImport) endif() + +add_RunCMake_test("CTestCommandExpandLists") diff --git a/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt new file mode 100644 index 0000000..3e470a2 --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.14) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in new file mode 100644 index 0000000..7d56c90 --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.14) +project(@CASE_NAME@ NONE) +include("@RunCMake_SOURCE_DIR@/@CASE_NAME@.cmake") diff --git a/Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake new file mode 100644 index 0000000..7c3779e --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake @@ -0,0 +1,5 @@ +include(RunCTest) + +run_ctest(expandGeneratorExpressionResult) +run_ctest(expandEmptyCommand) +run_cmake(multipleExpandOptions) diff --git a/Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake b/Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake new file mode 100644 index 0000000..a32e579 --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake @@ -0,0 +1,14 @@ +set(range 1 2 3 4 5 6 7 8 9 10) +set(aargs "") +set(bargs "") +foreach(n IN LISTS range) + set(aval "${A${n}ARG}") + set(bval "${B${n}ARG}") + if(aval OR bval) + list(APPEND aargs "\"${aval}\"") + list(APPEND bargs "\"${bval}\"") + endif() +endforeach() +if(NOT "${aargs}" STREQUAL "${bargs}") + message(FATAL_ERROR "COMPARE_OPTIONS: \n\t${aargs} != \n\t${bargs}") +endif() diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt new file mode 100644 index 0000000..c656b4c --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt @@ -0,0 +1 @@ +Unable to find executable: diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt new file mode 100644 index 0000000..0752580 --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt @@ -0,0 +1,13 @@ +Test project .*/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-build +.* +Start 1: CommandExpandEmptyList +Could not find executable + +Looked in the following places: +.* +1/1 Test #1: CommandExpandEmptyList +\.+\*\*\*Not Run +[0-9.]+ sec ++ +0% tests passed, 1 tests failed out of 1 ++ +Total Test time \(real\) = +[0-9.]+ sec ++ +The following tests FAILED: +.* +1 - CommandExpandEmptyList \(Not Run\)$ diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake new file mode 100644 index 0000000..b75828e --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake @@ -0,0 +1,10 @@ +include(CTest) + +set(argv /bin/true) +list(POP_BACK argv) + +add_test( + NAME CommandExpandEmptyList + COMMAND "$" + COMMAND_EXPAND_LISTS +) diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt new file mode 100644 index 0000000..2f21592 --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt @@ -0,0 +1,7 @@ +Test project .*/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-build +.* +Start 1: CommandExpandList +1/1 Test #1: CommandExpandList +\.+ +Passed +[0-9.]+ sec ++ +100% tests passed, 0 tests failed out of 1 ++ +Total Test time \(real\) = +[0-9.]+ sec diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake new file mode 100644 index 0000000..20608ae --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake @@ -0,0 +1,19 @@ +include(CTest) + + +set(cmp_args "1ARG=COMMAND_EXPAND_LISTS" "2ARG=test" "3ARG=outfile" + "4ARG=content") +set(AARGS "") +foreach(arg IN LISTS cmp_args) + list(APPEND AARGS "-DA${arg}") +endforeach() + + + +add_test( + NAME CommandExpandList + COMMAND ${CMAKE_COMMAND} ${AARGS} -V + "-DB$" + "-P" "${CMAKE_CURRENT_LIST_DIR}/compare_options.cmake" + COMMAND_EXPAND_LISTS +) diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt new file mode 100644 index 0000000..e48513f --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at multipleExpandOptions\.cmake:3 \(add_test\): + +add_test may be given at most one COMMAND_EXPAND_LISTS\. diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt new file mode 100644 index 0000000..55bb894 --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt @@ -0,0 +1,2 @@ +-- Configuring incomplete, errors occurred! +See also ".*/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-build/CMakeFiles/CMakeOutput\.log". diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake new file mode 100644 index 0000000..dcf2dc4 --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake @@ -0,0 +1,8 @@ +include(CTest) + +add_test( + NAME MultipleExpandOptions + COMMAND /bin/true + COMMAND_EXPAND_LISTS + COMMAND_EXPAND_LISTS +) diff --git a/Tests/RunCMake/CTestCommandExpandLists/test.cmake.in b/Tests/RunCMake/CTestCommandExpandLists/test.cmake.in new file mode 100644 index 0000000..d9a8ccb --- /dev/null +++ b/Tests/RunCMake/CTestCommandExpandLists/test.cmake.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.14) + +set(CTEST_SITE "test-site") +set(CTEST_BUILD_NAME "test-build-name") +set(CTEST_SOURCE_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@") +set(CTEST_BINARY_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@-build") +set(CTEST_CMAKE_GENERATOR "@RunCMake_GENERATOR@") +set(CTEST_CMAKE_GENERATOR_PLATFORM "@RunCMake_GENERATOR_PLATFORM@") +set(CTEST_CMAKE_GENERATOR_TOOLSET "@RunCMake_GENERATOR_TOOLSET@") +set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}") + +ctest_start(Experimental) +ctest_configure() +ctest_build() +ctest_test() -- cgit v0.12