From 5489ce74b349ed31d6abb6ee5a0aaa17b10b474d Mon Sep 17 00:00:00 2001 From: Zack Galbreath Date: Thu, 1 Jul 2021 12:40:41 -0400 Subject: ctest: support for runtime measurements Teach CTest to parse output for in addition to for measurements defined at runtime. Use a new class (cmCTestTestMeasurementXMLParser) derived from cmXMLParser to parse the data and attributes these XML elements. This is an improvement over our previous approach of using a series of regular expressions. As part of this commit we also rename some member variables and methods to make their purpose more clear. DartStuff -> AllTestMeasurementsRegex DartStuff1 -> SingleTestMeasurementRegex DartString -> TestMeasurementsOutput GenerateDartOutput() -> GenerateCTestXML() GenerateRegressionImages() -> RecordCustomTestMeasurements() cmCTestRunTest::DartProcessing() -> ParseOutputForMeasurements() --- Help/command/ctest_test.rst | 30 ++-- Source/CMakeLists.txt | 1 + Source/CTest/cmCTestMemCheckHandler.cxx | 2 +- Source/CTest/cmCTestMemCheckHandler.h | 4 +- Source/CTest/cmCTestRunTest.cxx | 20 ++- Source/CTest/cmCTestRunTest.h | 2 +- Source/CTest/cmCTestTestHandler.cxx | 192 ++++++--------------- Source/CTest/cmCTestTestHandler.h | 12 +- Source/CTest/cmCTestTestMeasurementXMLParser.cxx | 26 +++ Source/CTest/cmCTestTestMeasurementXMLParser.h | 21 +++ Tests/RunCMake/ctest_test/RunCMakeTest.cmake | 12 ++ .../ctest_test/TestMeasurements-check.cmake | 18 ++ 12 files changed, 171 insertions(+), 169 deletions(-) create mode 100644 Source/CTest/cmCTestTestMeasurementXMLParser.cxx create mode 100644 Source/CTest/cmCTestTestMeasurementXMLParser.h diff --git a/Help/command/ctest_test.rst b/Help/command/ctest_test.rst index 03ec1a4..caac605 100644 --- a/Help/command/ctest_test.rst +++ b/Help/command/ctest_test.rst @@ -186,29 +186,33 @@ Check the `CDash test measurement documentation `_ for more information on the types of test measurements that CDash recognizes. +Starting in version 3.22, CTest can parse custom measurements from tags named +```` or ````. The older names +```` and ```` are still supported. + The following example demonstrates how to output a variety of custom test measurements. .. code-block:: c++ std::cout << - "28.3" + "28.3" << std::endl; std::cout << - "red" + "red" << std::endl; std::cout << - "https://cmake.org" + "https://cmake.org" << std::endl; std::cout << - "" << + "" << "line 1.\n" << " \033[31;1m line 2. Bold red, and indented!\033[0;0ml\n" << "line 3. Not bold or indented...\n" << - "" << std::endl; + "" << std::endl; Image Measurements """""""""""""""""" @@ -218,16 +222,16 @@ The following example demonstrates how to upload test images to CDash. .. code-block:: c++ std::cout << - "" << - "/dir/to/test_img.jpg" << std::endl; + "" << + "/dir/to/test_img.jpg" << std::endl; std::cout << - "" << - "/dir/to/valid_img.gif" << std::endl; + "" << + "/dir/to/valid_img.gif" << std::endl; std::cout << - " << - "/dir/to/img.png" + " << + "/dir/to/img.png" << std::endl; Images will be displayed together in an interactive comparison mode on CDash @@ -253,8 +257,8 @@ The following example demonstrates how to upload non-image files to CDash. .. code-block:: c++ std::cout << - "" << - "/dir/to/data.csv" << std::endl; + "" << + "/dir/to/data.csv" << std::endl; If the name of the file to upload is known at configure time, you can use the :prop_test:`ATTACHED_FILES` or :prop_test:`ATTACHED_FILES_ON_FAIL` test diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 6446b04..d8ba784 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -960,6 +960,7 @@ set(CTEST_SRCS cmCTest.cxx CTest/cmCTestSubmitHandler.cxx CTest/cmCTestTestCommand.cxx CTest/cmCTestTestHandler.cxx + CTest/cmCTestTestMeasurementXMLParser.cxx CTest/cmCTestUpdateCommand.cxx CTest/cmCTestUpdateHandler.cxx CTest/cmCTestUploadCommand.cxx diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 125d003..6bb8e79 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -305,7 +305,7 @@ int cmCTestMemCheckHandler::GetDefectCount() const return this->DefectCount; } -void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) +void cmCTestMemCheckHandler::GenerateCTestXML(cmXMLWriter& xml) { if (!this->CTest->GetProduceXML()) { return; diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index b200c43..a63a24d 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -119,9 +119,9 @@ private: bool InitializeMemoryChecking(); /** - * Generate the Dart compatible output + * Generate CTest DynamicAnalysis.xml files */ - void GenerateDartOutput(cmXMLWriter& xml) override; + void GenerateCTestXML(cmXMLWriter& xml) override; std::vector CustomPreMemCheck; std::vector CustomPostMemCheck; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 50072c5..4e9b0f0 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -262,7 +262,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) *this->TestHandler->LogFile << "Test time = " << buf << std::endl; } - this->DartProcessing(); + this->ParseOutputForMeasurements(); // if this is doing MemCheck then all the output needs to be put into // Output since that is what is parsed by cmCTestMemCheckHandler @@ -698,18 +698,22 @@ void cmCTestRunTest::ComputeArguments() } } -void cmCTestRunTest::DartProcessing() +void cmCTestRunTest::ParseOutputForMeasurements() { if (!this->ProcessOutput.empty() && - this->ProcessOutput.find("TestHandler->DartStuff.find(this->ProcessOutput)) { - this->TestResult.DartString = this->TestHandler->DartStuff.match(1); + (this->ProcessOutput.find("ProcessOutput.find("TestHandler->AllTestMeasurementsRegex.find( + this->ProcessOutput)) { + this->TestResult.TestMeasurementsOutput = + this->TestHandler->AllTestMeasurementsRegex.match(1); // keep searching and replacing until none are left - while (this->TestHandler->DartStuff1.find(this->ProcessOutput)) { + while (this->TestHandler->SingleTestMeasurementRegex.find( + this->ProcessOutput)) { // replace the exact match for the string cmSystemTools::ReplaceString( - this->ProcessOutput, this->TestHandler->DartStuff1.match(1).c_str(), - ""); + this->ProcessOutput, + this->TestHandler->SingleTestMeasurementRegex.match(1).c_str(), ""); } } } diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 863ac1b..a4981c3 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -109,7 +109,7 @@ public: private: bool NeedsToRepeat(); - void DartProcessing(); + void ParseOutputForMeasurements(); void ExeNotFound(std::string exe); bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, std::vector* environment, diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index aeaf696..72b86c1 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -32,6 +32,7 @@ #include "cmCTest.h" #include "cmCTestMultiProcessHandler.h" #include "cmCTestResourceGroupsLexerHelper.h" +#include "cmCTestTestMeasurementXMLParser.h" #include "cmDuration.h" #include "cmExecutionStatus.h" #include "cmGeneratedFileStream.h" @@ -303,16 +304,23 @@ cmCTestTestHandler::cmCTestTestHandler() // Support for JUnit XML output. this->JUnitXMLFileName = ""; - // regex to detect ... - this->DartStuff.compile("()"); - // regex to detect each individual ... - this->DartStuff1.compile( - "()"); + // Regular expressions to scan test output for custom measurements. - // regex to detect ... + // Capture the whole section of test output from the first opening + // <(CTest|Dart)Measurement*> tag to the last + // closing tag. + this->AllTestMeasurementsRegex.compile( + "(<(CTest|Dart)Measurement.*/(CTest|Dart)Measurement[a-zA-Z]*>)"); + + // Capture a single <(CTest|Dart)Measurement*> XML element. + this->SingleTestMeasurementRegex.compile( + "(<(CTest|Dart)Measurement[^<]*)"); + + // Capture content from ... this->CustomCompletionStatusRegex.compile( "(.*)"); - // regex to detect ... + + // Capture content from ... this->CustomLabelRegex.compile("(.*)"); } @@ -694,7 +702,7 @@ bool cmCTestTestHandler::GenerateXML() return false; } cmXMLWriter xml(xmlfile); - this->GenerateDartOutput(xml); + this->GenerateCTestXML(xml); } return true; @@ -1402,7 +1410,7 @@ void cmCTestTestHandler::GenerateTestCommand( { } -void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) +void cmCTestTestHandler::GenerateCTestXML(cmXMLWriter& xml) { if (!this->CTest->GetProduceXML()) { return; @@ -1438,7 +1446,7 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.Element("Value", result.ReturnValue); xml.EndElement(); // NamedMeasurement } - this->GenerateRegressionImages(xml, result.DartString); + this->RecordCustomTestMeasurements(xml, result.TestMeasurementsOutput); xml.StartElement("NamedMeasurement"); xml.Attribute("type", "numeric/double"); xml.Attribute("name", "Execution Time"); @@ -1978,124 +1986,48 @@ void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed() } } -// Just for convenience -#define SPACE_REGEX "[ \t\r\n]" -void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, - const std::string& dart) -{ - cmsys::RegularExpression twoattributes( - "([^<]*)"); - cmsys::RegularExpression threeattributes( - "([^<]*)"); - cmsys::RegularExpression fourattributes( - "([^<]*)"); - cmsys::RegularExpression cdatastart( - "" SPACE_REGEX "*" SPACE_REGEX "*"); - cmsys::RegularExpression measurementfile( - "([^<]*)"); - - bool done = false; - std::string cxml = dart; - while (!done) { - if (twoattributes.find(cxml)) { - xml.StartElement("NamedMeasurement"); - xml.Attribute(twoattributes.match(1).c_str(), twoattributes.match(2)); - xml.Attribute(twoattributes.match(3).c_str(), twoattributes.match(4)); - xml.Element("Value", twoattributes.match(5)); - xml.EndElement(); - cxml.erase(twoattributes.start(), - twoattributes.end() - twoattributes.start()); - } else if (threeattributes.find(cxml)) { - xml.StartElement("NamedMeasurement"); - xml.Attribute(threeattributes.match(1).c_str(), - threeattributes.match(2)); - xml.Attribute(threeattributes.match(3).c_str(), - threeattributes.match(4)); - xml.Attribute(threeattributes.match(5).c_str(), - threeattributes.match(6)); - xml.Element("Value", twoattributes.match(7)); - xml.EndElement(); - cxml.erase(threeattributes.start(), - threeattributes.end() - threeattributes.start()); - } else if (fourattributes.find(cxml)) { +void cmCTestTestHandler::RecordCustomTestMeasurements(cmXMLWriter& xml, + std::string content) +{ + while (this->SingleTestMeasurementRegex.find(content)) { + // Extract regex match from content and parse it as an XML element. + auto measurement_str = this->SingleTestMeasurementRegex.match(1); + auto parser = cmCTestTestMeasurementXMLParser(); + parser.Parse(measurement_str.c_str()); + + if (parser.ElementName == "CTestMeasurement" || + parser.ElementName == "DartMeasurement") { xml.StartElement("NamedMeasurement"); - xml.Attribute(fourattributes.match(1).c_str(), fourattributes.match(2)); - xml.Attribute(fourattributes.match(3).c_str(), fourattributes.match(4)); - xml.Attribute(fourattributes.match(5).c_str(), fourattributes.match(6)); - xml.Attribute(fourattributes.match(7).c_str(), fourattributes.match(8)); - xml.Element("Value", twoattributes.match(9)); + xml.Attribute("type", parser.MeasurementType); + xml.Attribute("name", parser.MeasurementName); + xml.Element("Value", parser.CharacterData); xml.EndElement(); - cxml.erase(fourattributes.start(), - fourattributes.end() - fourattributes.start()); - } else if (cdatastart.find(cxml) && cdataend.find(cxml)) { - xml.StartElement("NamedMeasurement"); - xml.Attribute(cdatastart.match(1).c_str(), cdatastart.match(2)); - xml.Attribute(cdatastart.match(3).c_str(), cdatastart.match(4)); - xml.StartElement("Value"); - xml.CData( - cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end())); - xml.EndElement(); // Value - xml.EndElement(); // NamedMeasurement - cxml.erase(cdatastart.start(), cdataend.end() - cdatastart.start()); - } else if (measurementfile.find(cxml)) { - const std::string& filename = - cmCTest::CleanString(measurementfile.match(5)); - if (cmSystemTools::FileExists(filename)) { + } else if (parser.ElementName == "CTestMeasurementFile" || + parser.ElementName == "DartMeasurementFile") { + const std::string& filename = cmCTest::CleanString(parser.CharacterData); + if (!cmSystemTools::FileExists(filename)) { + xml.StartElement("NamedMeasurement"); + xml.Attribute("name", parser.MeasurementName); + xml.Attribute("text", "text/string"); + xml.Element("Value", "File " + filename + " not found"); + xml.EndElement(); + cmCTestOptionalLog( + this->CTest, HANDLER_OUTPUT, + "File \"" << filename << "\" not found." << std::endl, this->Quiet); + } else { long len = cmSystemTools::FileLength(filename); - std::string k1 = measurementfile.match(1); - std::string v1 = measurementfile.match(2); - std::string k2 = measurementfile.match(3); - std::string v2 = measurementfile.match(4); if (len == 0) { - if (cmSystemTools::LowerCase(k1) == "type") { - v1 = "text/string"; - } - if (cmSystemTools::LowerCase(k2) == "type") { - v2 = "text/string"; - } - xml.StartElement("NamedMeasurement"); - xml.Attribute(k1.c_str(), v1); - xml.Attribute(k2.c_str(), v2); + xml.Attribute("name", parser.MeasurementName); + xml.Attribute("type", "text/string"); xml.Attribute("encoding", "none"); xml.Element("Value", "Image " + filename + " is empty"); xml.EndElement(); } else { - std::string type; - std::string name; - if (cmSystemTools::LowerCase(k1) == "type") { - type = v1; - } else if (cmSystemTools::LowerCase(k2) == "type") { - type = v2; - } - if (cmSystemTools::LowerCase(k1) == "name") { - name = v1; - } else if (cmSystemTools::LowerCase(k2) == "name") { - name = v2; - } - if (type == "file") { + if (parser.MeasurementType == "file") { // Treat this measurement like an "ATTACHED_FILE" when the type // is explicitly "file" (not an image). - this->AttachFile(xml, filename, name); + this->AttachFile(xml, filename, parser.MeasurementName); } else { cmsys::ifstream ifs(filename.c_str(), std::ios::in @@ -2112,10 +2044,8 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, encoded_buffer.get(), 1); xml.StartElement("NamedMeasurement"); - xml.Attribute(measurementfile.match(1).c_str(), - measurementfile.match(2)); - xml.Attribute(measurementfile.match(3).c_str(), - measurementfile.match(4)); + xml.Attribute("name", parser.MeasurementName); + xml.Attribute("type", parser.MeasurementType); xml.Attribute("encoding", "base64"); std::ostringstream ostr; for (size_t cc = 0; cc < rlen; cc++) { @@ -2128,25 +2058,11 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, xml.EndElement(); // NamedMeasurement } } - } else { - int idx = 4; - if (measurementfile.match(1) == "name") { - idx = 2; - } - xml.StartElement("NamedMeasurement"); - xml.Attribute("name", measurementfile.match(idx)); - xml.Attribute("text", "text/string"); - xml.Element("Value", "File " + filename + " not found"); - xml.EndElement(); - cmCTestOptionalLog( - this->CTest, HANDLER_OUTPUT, - "File \"" << filename << "\" not found." << std::endl, this->Quiet); } - cxml.erase(measurementfile.start(), - measurementfile.end() - measurementfile.start()); - } else { - done = true; } + + // Remove this element from content. + cmSystemTools::ReplaceString(content, measurement_str.c_str(), ""); } } diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index cc19984..1b42647 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -177,7 +177,7 @@ public: std::string CompletionStatus; std::string CustomCompletionStatus; std::string Output; - std::string DartString; + std::string TestMeasurementsOutput; int TestCount; cmCTestTestProperties* Properties; }; @@ -276,9 +276,9 @@ public: private: /** - * Generate the Dart compatible output + * Write test results in CTest's Test.xml format */ - virtual void GenerateDartOutput(cmXMLWriter& xml); + virtual void GenerateCTestXML(cmXMLWriter& xml); /** * Write test results in JUnit XML format @@ -348,8 +348,7 @@ private: cmCTestResourceSpec ResourceSpec; std::string ResourceSpecFile; - void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart); - cmsys::RegularExpression DartStuff1; + void RecordCustomTestMeasurements(cmXMLWriter& xml, std::string content); void CheckLabelFilter(cmCTestTestProperties& it); void CheckLabelFilterExclude(cmCTestTestProperties& it); void CheckLabelFilterInclude(cmCTestTestProperties& it); @@ -358,7 +357,8 @@ private: bool UseUnion; ListOfTests TestList; size_t TotalNumberOfTests; - cmsys::RegularExpression DartStuff; + cmsys::RegularExpression AllTestMeasurementsRegex; + cmsys::RegularExpression SingleTestMeasurementRegex; cmsys::RegularExpression CustomCompletionStatusRegex; cmsys::RegularExpression CustomLabelRegex; diff --git a/Source/CTest/cmCTestTestMeasurementXMLParser.cxx b/Source/CTest/cmCTestTestMeasurementXMLParser.cxx new file mode 100644 index 0000000..636be24 --- /dev/null +++ b/Source/CTest/cmCTestTestMeasurementXMLParser.cxx @@ -0,0 +1,26 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmCTestTestMeasurementXMLParser.h" + +#include + +void cmCTestTestMeasurementXMLParser::StartElement(const std::string& name, + const char** attributes) +{ + this->CharacterData.clear(); + this->ElementName = name; + for (const char** attr = attributes; *attr; attr += 2) { + if (strcmp(attr[0], "name") == 0) { + this->MeasurementName = attr[1]; + } else if (strcmp(attr[0], "type") == 0) { + this->MeasurementType = attr[1]; + } + } +} + +void cmCTestTestMeasurementXMLParser::CharacterDataHandler(const char* data, + int length) +{ + this->CharacterData.append(data, length); +} diff --git a/Source/CTest/cmCTestTestMeasurementXMLParser.h b/Source/CTest/cmCTestTestMeasurementXMLParser.h new file mode 100644 index 0000000..b2c3eb3 --- /dev/null +++ b/Source/CTest/cmCTestTestMeasurementXMLParser.h @@ -0,0 +1,21 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include + +#include "cmXMLParser.h" + +class cmCTestTestMeasurementXMLParser : public cmXMLParser +{ +public: + cmCTestTestMeasurementXMLParser() {} + std::string CharacterData; + std::string ElementName; + std::string MeasurementName; + std::string MeasurementType; + +protected: + void StartElement(const std::string& name, const char** atts) override; + void EndElement(const std::string& /*name*/) override {} + void CharacterDataHandler(const char* data, int length) override; +}; diff --git a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake index 31bc075..a211c66 100644 --- a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake @@ -158,13 +158,25 @@ add_test( COMMAND ${CMAKE_COMMAND} -E echo 1.4847) add_test( + NAME double_measurement2 + COMMAND ${CMAKE_COMMAND} -E + echo 1.8474) +add_test( NAME img_measurement COMMAND ${CMAKE_COMMAND} -E echo ]] ${IMAGE_DIR}/cmake-logo-16.png [[) add_test( + NAME img_measurement2 + COMMAND ${CMAKE_COMMAND} -E + echo ]] ${IMAGE_DIR}/cmake-logo-16.png [[) +add_test( NAME file_measurement COMMAND ${CMAKE_COMMAND} -E echo ]] ${IMAGE_DIR}/cmake-logo-16.png [[) +add_test( + NAME file_measurement2 + COMMAND ${CMAKE_COMMAND} -E + echo ]] ${IMAGE_DIR}/cmake-logo-16.png [[) ]]) run_ctest(TestMeasurements) endfunction() diff --git a/Tests/RunCMake/ctest_test/TestMeasurements-check.cmake b/Tests/RunCMake/ctest_test/TestMeasurements-check.cmake index 0095db0..7e0928d 100644 --- a/Tests/RunCMake/ctest_test/TestMeasurements-check.cmake +++ b/Tests/RunCMake/ctest_test/TestMeasurements-check.cmake @@ -10,13 +10,31 @@ endif() if(NOT _test_contents MATCHES "1.4847") string(APPEND RunCMake_TEST_FAILED "Could not find expected measurement value in Test.xml") endif() +# Check the other double measurement. +if(NOT _test_contents MATCHES [[NamedMeasurement type="numeric/double" name="another_custom_value"]]) + string(APPEND RunCMake_TEST_FAILED + "Could not find expected tag(2) for type='numeric/double' in Test.xml") +endif() +if(NOT _test_contents MATCHES "1.8474") + string(APPEND RunCMake_TEST_FAILED "Could not find expected measurement value(2) in Test.xml") +endif() # Check img measurement. if(NOT _test_contents MATCHES [[NamedMeasurement name="TestImage" type="image/png" encoding="base64"]]) string(APPEND RunCMake_TEST_FAILED "Could not find expected tag for type='image/png' in Test.xml") endif() +# Check img measurement 2. +if(NOT _test_contents MATCHES [[NamedMeasurement name="TestImage2" type="image/png" encoding="base64"]]) + string(APPEND RunCMake_TEST_FAILED + "Could not find expected tag(2) for type='image/png' in Test.xml") +endif() # Check file measurement. if(NOT _test_contents MATCHES [[NamedMeasurement name="my_test_input_data" encoding="base64" compression="tar/gzip" filename="cmake-logo-16.png" type="file"]]) string(APPEND RunCMake_TEST_FAILED "Could not find expected tag for type='file' in Test.xml") endif() +# Check file measurement 2. +if(NOT _test_contents MATCHES [[NamedMeasurement name="another_test_input_data" encoding="base64" compression="tar/gzip" filename="cmake-logo-16.png" type="file"]]) + string(APPEND RunCMake_TEST_FAILED + "Could not find expected tag(2) for type='file' in Test.xml") +endif() -- cgit v0.12