mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-05 21:31:08 -06:00
ctest: support <CTestMeasurement> for runtime measurements
Teach CTest to parse output for <CTestMeasurement> in addition to <DartMeasurement> 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()
This commit is contained in:
@@ -186,29 +186,33 @@ Check the `CDash test measurement documentation
|
||||
<https://github.com/Kitware/CDash/blob/master/docs/test_measurements.md>`_
|
||||
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
|
||||
``<CTestMeasurement>`` or ``<CTestMeasurementFile>``. The older names
|
||||
``<DartMeasurement>`` and ``<DartMeasurementFile>`` are still supported.
|
||||
|
||||
The following example demonstrates how to output a variety of custom test
|
||||
measurements.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
std::cout <<
|
||||
"<DartMeasurement type=\"numeric/double\" name=\"score\">28.3</DartMeasurement>"
|
||||
"<CTestMeasurement type=\"numeric/double\" name=\"score\">28.3</CTestMeasurement>"
|
||||
<< std::endl;
|
||||
|
||||
std::cout <<
|
||||
"<DartMeasurement type=\"text/string\" name=\"color\">red</DartMeasurement>"
|
||||
"<CTestMeasurement type=\"text/string\" name=\"color\">red</CTestMeasurement>"
|
||||
<< std::endl;
|
||||
|
||||
std::cout <<
|
||||
"<DartMeasurement type=\"text/link\" name=\"CMake URL\">https://cmake.org</DartMeasurement>"
|
||||
"<CTestMeasurement type=\"text/link\" name=\"CMake URL\">https://cmake.org</CTestMeasurement>"
|
||||
<< std::endl;
|
||||
|
||||
std::cout <<
|
||||
"<DartMeasurement type=\"text/preformatted\" name=\"Console Output\">" <<
|
||||
"<CTestMeasurement type=\"text/preformatted\" name=\"Console Output\">" <<
|
||||
"line 1.\n" <<
|
||||
" \033[31;1m line 2. Bold red, and indented!\033[0;0ml\n" <<
|
||||
"line 3. Not bold or indented...\n" <<
|
||||
"</DartMeasurement>" << std::endl;
|
||||
"</CTestMeasurement>" << std::endl;
|
||||
|
||||
Image Measurements
|
||||
""""""""""""""""""
|
||||
@@ -218,16 +222,16 @@ The following example demonstrates how to upload test images to CDash.
|
||||
.. code-block:: c++
|
||||
|
||||
std::cout <<
|
||||
"<DartMeasurementFile type=\"image/jpg\" name=\"TestImage\">" <<
|
||||
"/dir/to/test_img.jpg</DartMeasurementFile>" << std::endl;
|
||||
"<CTestMeasurementFile type=\"image/jpg\" name=\"TestImage\">" <<
|
||||
"/dir/to/test_img.jpg</CTestMeasurementFile>" << std::endl;
|
||||
|
||||
std::cout <<
|
||||
"<DartMeasurementFile type=\"image/gif\" name=\"ValidImage\">" <<
|
||||
"/dir/to/valid_img.gif</DartMeasurementFile>" << std::endl;
|
||||
"<CTestMeasurementFile type=\"image/gif\" name=\"ValidImage\">" <<
|
||||
"/dir/to/valid_img.gif</CTestMeasurementFile>" << std::endl;
|
||||
|
||||
std::cout <<
|
||||
"<DartMeasurementFile type=\"image/png\" name=\"AlgoResult\"> <<
|
||||
"/dir/to/img.png</DartMeasurementFile>"
|
||||
"<CTestMeasurementFile type=\"image/png\" name=\"AlgoResult\"> <<
|
||||
"/dir/to/img.png</CTestMeasurementFile>"
|
||||
<< 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 <<
|
||||
"<DartMeasurementFile type=\"file\" name=\"MyTestInputData\">" <<
|
||||
"/dir/to/data.csv</DartMeasurementFile>" << std::endl;
|
||||
"<CTestMeasurementFile type=\"file\" name=\"MyTestInputData\">" <<
|
||||
"/dir/to/data.csv</CTestMeasurementFile>" << 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<std::string> CustomPreMemCheck;
|
||||
std::vector<std::string> CustomPostMemCheck;
|
||||
|
||||
@@ -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("<DartMeasurement") != std::string::npos) {
|
||||
if (this->TestHandler->DartStuff.find(this->ProcessOutput)) {
|
||||
this->TestResult.DartString = this->TestHandler->DartStuff.match(1);
|
||||
(this->ProcessOutput.find("<DartMeasurement") != std::string::npos ||
|
||||
this->ProcessOutput.find("<CTestMeasurement") != std::string::npos)) {
|
||||
if (this->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(), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<std::string>* environment,
|
||||
|
||||
@@ -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 <DartMeasurement>...</DartMeasurement>
|
||||
this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
|
||||
// regex to detect each individual <DartMeasurement>...</DartMeasurement>
|
||||
this->DartStuff1.compile(
|
||||
"(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
|
||||
// Regular expressions to scan test output for custom measurements.
|
||||
|
||||
// regex to detect <CTestDetails>...</CTestDetails>
|
||||
// Capture the whole section of test output from the first opening
|
||||
// <(CTest|Dart)Measurement*> tag to the last </(CTest|Dart)Measurement*>
|
||||
// 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[^<]*</(CTest|Dart)Measurement[a-zA-Z]*>)");
|
||||
|
||||
// Capture content from <CTestDetails>...</CTestDetails>
|
||||
this->CustomCompletionStatusRegex.compile(
|
||||
"<CTestDetails>(.*)</CTestDetails>");
|
||||
// regex to detect <CTestLabel>...</CTestLabel>
|
||||
|
||||
// Capture content from <CTestLabel>...</CTestLabel>
|
||||
this->CustomLabelRegex.compile("<CTestLabel>(.*)</CTestLabel>");
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
void cmCTestTestHandler::RecordCustomTestMeasurements(cmXMLWriter& xml,
|
||||
std::string content)
|
||||
{
|
||||
cmsys::RegularExpression twoattributes(
|
||||
"<DartMeasurement" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*>([^<]*)</DartMeasurement>");
|
||||
cmsys::RegularExpression threeattributes(
|
||||
"<DartMeasurement" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*>([^<]*)</DartMeasurement>");
|
||||
cmsys::RegularExpression fourattributes(
|
||||
"<DartMeasurement" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*>([^<]*)</DartMeasurement>");
|
||||
cmsys::RegularExpression cdatastart(
|
||||
"<DartMeasurement" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*>" SPACE_REGEX "*<!\\[CDATA\\[");
|
||||
cmsys::RegularExpression cdataend("]]>" SPACE_REGEX "*</DartMeasurement>");
|
||||
cmsys::RegularExpression measurementfile(
|
||||
"<DartMeasurementFile" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
|
||||
"*>([^<]*)</DartMeasurementFile>");
|
||||
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());
|
||||
|
||||
bool done = false;
|
||||
std::string cxml = dart;
|
||||
while (!done) {
|
||||
if (twoattributes.find(cxml)) {
|
||||
if (parser.ElementName == "CTestMeasurement" ||
|
||||
parser.ElementName == "DartMeasurement") {
|
||||
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.Attribute("type", parser.MeasurementType);
|
||||
xml.Attribute("name", parser.MeasurementName);
|
||||
xml.Element("Value", parser.CharacterData);
|
||||
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)) {
|
||||
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.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(), "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
26
Source/CTest/cmCTestTestMeasurementXMLParser.cxx
Normal file
26
Source/CTest/cmCTestTestMeasurementXMLParser.cxx
Normal file
@@ -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 <cstring>
|
||||
|
||||
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);
|
||||
}
|
||||
21
Source/CTest/cmCTestTestMeasurementXMLParser.h
Normal file
21
Source/CTest/cmCTestTestMeasurementXMLParser.h
Normal file
@@ -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 <string>
|
||||
|
||||
#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;
|
||||
};
|
||||
@@ -157,14 +157,26 @@ add_test(
|
||||
NAME double_measurement
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
echo <DartMeasurement type="numeric/double" name="my_custom_value">1.4847</DartMeasurement>)
|
||||
add_test(
|
||||
NAME double_measurement2
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
echo <CTestMeasurement type="numeric/double" name="another_custom_value">1.8474</CTestMeasurement>)
|
||||
add_test(
|
||||
NAME img_measurement
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
echo <DartMeasurementFile name="TestImage" type="image/png">]] ${IMAGE_DIR}/cmake-logo-16.png [[</DartMeasurementFile>)
|
||||
add_test(
|
||||
NAME img_measurement2
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
echo <CTestMeasurementFile name="TestImage2" type="image/png">]] ${IMAGE_DIR}/cmake-logo-16.png [[</CTestMeasurementFile>)
|
||||
add_test(
|
||||
NAME file_measurement
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
echo <DartMeasurementFile name="my_test_input_data" type="file">]] ${IMAGE_DIR}/cmake-logo-16.png [[</DartMeasurementFile>)
|
||||
add_test(
|
||||
NAME file_measurement2
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
echo <CTestMeasurementFile name="another_test_input_data" type="file">]] ${IMAGE_DIR}/cmake-logo-16.png [[</CTestMeasurementFile>)
|
||||
]])
|
||||
run_ctest(TestMeasurements)
|
||||
endfunction()
|
||||
|
||||
@@ -10,13 +10,31 @@ endif()
|
||||
if(NOT _test_contents MATCHES "<Value>1.4847</Value>")
|
||||
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 <NamedMeasurement> tag(2) for type='numeric/double' in Test.xml")
|
||||
endif()
|
||||
if(NOT _test_contents MATCHES "<Value>1.8474</Value>")
|
||||
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 <NamedMeasurement> 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 <NamedMeasurement> 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 <NamedMeasurement> 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 <NamedMeasurement> tag(2) for type='file' in Test.xml")
|
||||
endif()
|
||||
|
||||
Reference in New Issue
Block a user