summaryrefslogtreecommitdiffstats
path: root/Source/cmTestGenerator.cxx
diff options
context:
space:
mode:
authorDeniz Bahadir <dbahadir@benocs.com>2020-05-15 23:52:34 (GMT)
committerBrad King <brad.king@kitware.com>2020-08-12 14:44:07 (GMT)
commita20987732bbd8d7e86501e42b2b5a72d60d02805 (patch)
tree89f416b8548c649d89e7d1108cc0905058a43ff0 /Source/cmTestGenerator.cxx
parentd6ee9b4a43210553b8f4d3a11413f744e2affb26 (diff)
downloadCMake-a20987732bbd8d7e86501e42b2b5a72d60d02805.zip
CMake-a20987732bbd8d7e86501e42b2b5a72d60d02805.tar.gz
CMake-a20987732bbd8d7e86501e42b2b5a72d60d02805.tar.bz2
add_test: Allow special characters in test name (w/ policy CMP0110)
Restore the change from commit f84af8e270 (add_test: Allow special characters in test name, 2020-05-16, v3.18.0-rc1~142^2) that had to be reverted by commit f84af8e270 (add_test: Allow special characters in test name, 2020-05-16, v3.18.0-rc1~142^2) for compatibility. Add policy CMP0110 to make the change in a compatible way. Also, support even more characters than before by generating the test scripts using bracket arguments around the test names. Fixes: #19391 Signed-off-by: Deniz Bahadir <dbahadir@benocs.com>
Diffstat (limited to 'Source/cmTestGenerator.cxx')
-rw-r--r--Source/cmTestGenerator.cxx121
1 files changed, 112 insertions, 9 deletions
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 78b230c..da4593f 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -2,8 +2,12 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTestGenerator.h"
+#include <algorithm>
+#include <cstddef> // IWYU pragma: keep
+#include <iterator>
#include <memory>
#include <ostream>
+#include <string>
#include <utility>
#include <vector>
@@ -11,7 +15,10 @@
#include "cmGeneratorTarget.h"
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmOutputConverter.h"
+#include "cmPolicies.h"
#include "cmProperty.h"
#include "cmPropertyMap.h"
#include "cmRange.h"
@@ -20,6 +27,52 @@
#include "cmSystemTools.h"
#include "cmTest.h"
+namespace /* anonymous */
+{
+
+bool needToQuoteTestName(const cmMakefile& mf, const std::string& name)
+{
+ // Determine if policy CMP0110 is set to NEW.
+ switch (mf.GetPolicyStatus(cmPolicies::CMP0110)) {
+ case cmPolicies::WARN:
+ // Only warn if a forbidden character is used in the name.
+ if (name.find_first_of("$[] #;\t\n\"\\") != std::string::npos) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0110),
+ "\nThe following name given to add_test() is invalid if "
+ "CMP0110 is not set or set to OLD:\n `",
+ name, "ยด\n"));
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to not quote the test's name.
+ return false;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ default:
+ // NEW behavior is to quote the test's name.
+ return true;
+ }
+}
+
+std::size_t countMaxConsecutiveEqualSigns(const std::string& name)
+{
+ std::size_t max = 0;
+ auto startIt = find(name.begin(), name.end(), '=');
+ auto endIt = startIt;
+ for (; startIt != name.end(); startIt = find(endIt, name.end(), '=')) {
+ endIt =
+ find_if_not(startIt + 1, name.end(), [](char c) { return c == '='; });
+ max =
+ std::max(max, static_cast<std::size_t>(std::distance(startIt, endIt)));
+ }
+ return max;
+}
+
+} // End: anonymous namespace
+
cmTestGenerator::cmTestGenerator(
cmTest* test, std::vector<std::string> const& configurations)
: cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations)
@@ -76,8 +129,21 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
// Set up generator expression evaluation context.
cmGeneratorExpression ge(this->Test->GetBacktrace());
+ // Determine if policy CMP0110 is set to NEW.
+ const bool quote_test_name =
+ needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName());
+ // Determine the number of equal-signs needed for quoting test name with
+ // [==[...]==] syntax.
+ const std::string equalSigns(
+ 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '=');
+
// Start the test command.
- os << indent << "add_test(" << this->Test->GetName() << " ";
+ if (quote_test_name) {
+ os << indent << "add_test([" << equalSigns << "[" << this->Test->GetName()
+ << "]" << equalSigns << "] ";
+ } else {
+ os << indent << "add_test(" << this->Test->GetName() << " ";
+ }
// Evaluate command line arguments
std::vector<std::string> argv =
@@ -127,8 +193,13 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
os << ")\n";
// Output properties for the test.
- os << indent << "set_tests_properties(" << this->Test->GetName()
- << " PROPERTIES ";
+ if (quote_test_name) {
+ os << indent << "set_tests_properties([" << equalSigns << "["
+ << this->Test->GetName() << "]" << equalSigns << "] PROPERTIES ";
+ } else {
+ os << indent << "set_tests_properties(" << this->Test->GetName()
+ << " PROPERTIES ";
+ }
for (auto const& i : this->Test->GetProperties().GetList()) {
os << " " << i.first << " "
<< cmOutputConverter::EscapeForCMake(
@@ -140,7 +211,21 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent)
{
- os << indent << "add_test(" << this->Test->GetName() << " NOT_AVAILABLE)\n";
+ // Determine if policy CMP0110 is set to NEW.
+ const bool quote_test_name =
+ needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName());
+ // Determine the number of equal-signs needed for quoting test name with
+ // [==[...]==] syntax.
+ const std::string equalSigns(
+ 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '=');
+
+ if (quote_test_name) {
+ os << indent << "add_test([" << equalSigns << "[" << this->Test->GetName()
+ << "]" << equalSigns << "] NOT_AVAILABLE)\n";
+ } else {
+ os << indent << "add_test(" << this->Test->GetName()
+ << " NOT_AVAILABLE)\n";
+ }
}
bool cmTestGenerator::NeedsScriptNoConfig() const
@@ -155,14 +240,27 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
{
this->TestGenerated = true;
+ // Determine if policy CMP0110 is set to NEW.
+ const bool quote_test_name =
+ needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName());
+ // Determine the number of equal-signs needed for quoting test name with
+ // [==[...]==] syntax.
+ const std::string equalSigns(
+ 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '=');
+
// Get the test command line to be executed.
std::vector<std::string> const& command = this->Test->GetCommand();
std::string exe = command[0];
cmSystemTools::ConvertToUnixSlashes(exe);
- fout << indent;
- fout << "add_test(";
- fout << this->Test->GetName() << " \"" << exe << "\"";
+ if (quote_test_name) {
+ fout << indent << "add_test([" << equalSigns << "["
+ << this->Test->GetName() << "]" << equalSigns << "] \"" << exe
+ << "\"";
+ } else {
+ fout << indent << "add_test(" << this->Test->GetName() << " \"" << exe
+ << "\"";
+ }
for (std::string const& arg : cmMakeRange(command).advance(1)) {
// Just double-quote all arguments so they are re-parsed
@@ -182,8 +280,13 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
fout << ")\n";
// Output properties for the test.
- fout << indent << "set_tests_properties(" << this->Test->GetName()
- << " PROPERTIES ";
+ if (quote_test_name) {
+ fout << indent << "set_tests_properties([" << equalSigns << "["
+ << this->Test->GetName() << "]" << equalSigns << "] PROPERTIES ";
+ } else {
+ fout << indent << "set_tests_properties(" << this->Test->GetName()
+ << " PROPERTIES ";
+ }
for (auto const& i : this->Test->GetProperties().GetList()) {
fout << " " << i.first << " "
<< cmOutputConverter::EscapeForCMake(i.second);