37#include <boost/algorithm/string.hpp>
38#include <boost/core/ignore_unused.hpp>
39#include <boost/lexical_cast.hpp>
61 TiXmlElement *regex = metric->FirstChildElement(
"regex");
62 ASSERTL0(regex,
"No Regex defined.");
63 ASSERTL0(regex->GetText(),
"Failed to get text");
64 m_regex = std::regex(regex->GetText(), std::regex::ECMAScript);
72 TiXmlElement *matches = metric->FirstChildElement(
"matches");
73 ASSERTL0(matches,
"No matches defined.");
74 TiXmlElement *match = matches->FirstChildElement(
"match");
77 std::vector<MetricRegexFieldValue> tmp;
78 TiXmlElement *
field = match->FirstChildElement(
"field");
86 const char *tol =
field->Attribute(
"tolerance");
93 const char *intTol =
field->Attribute(
"inttolerance");
101 "Cannot use both integer and double tolerances.");
108 match = match->NextSiblingElement(
"match");
117 boost::ignore_unused(pStdout, pStderr);
122 std::istream &is =
m_useStderr ? pStderr : pStdout;
124 std::vector<MetricRegexFieldValue> &okValues =
m_matches[0];
127 bool matchedTol =
false;
132 while (getline(is, line) &&
m_matches.size() > 0)
137 if (std::regex_match(line, matches,
m_regex))
140 if (matches.size() == 1)
142 cerr <<
"No test sections in regex!" << endl;
147 for (
int i = 1; i < matches.size(); ++i)
150 std::string match(matches[i].first, matches[i].second);
152 if (okValues[i - 1].m_useTolerance)
157 val = fabs(fabs(boost::lexical_cast<double>(
158 okValues[i - 1].m_value)) -
159 fabs(boost::lexical_cast<double>(match)));
161 catch (boost::bad_lexical_cast &e)
163 cerr <<
"Could not convert one of " << match
164 <<
" (match) or " << okValues[i - 1].m_value
165 <<
" (comparison value) to double" << endl;
172 if (val > okValues[i - 1].m_tolerance)
180 cerr <<
"Failed tolerance match." << endl;
181 cerr <<
" Expected: " << okValues[i - 1].m_value
182 <<
" +/- " << okValues[i - 1].m_tolerance
184 cerr <<
" Result: " << match << endl;
189 else if (okValues[i - 1].m_useIntTolerance)
195 boost::lexical_cast<int>(okValues[i - 1].m_value) -
196 boost::lexical_cast<int>(match));
198 catch (boost::bad_lexical_cast &e)
200 cerr <<
"Could not convert one of " << match
201 <<
" (match) or " << okValues[i - 1].m_value
202 <<
" (comparison value) to an integer" << endl;
209 if (val > okValues[i - 1].m_intTolerance)
217 cerr <<
"Failed tolerance match." << endl;
218 cerr <<
" Expected: " << okValues[i - 1].m_value
219 <<
" +/- " << okValues[i - 1].m_intTolerance
221 cerr <<
" Result: " << match << endl;
229 if (!boost::iequals(match, okValues[i - 1].m_value))
237 cerr <<
"Failed case-insensitive match." << endl;
238 cerr <<
" Expected: " << okValues[i - 1].m_value
240 cerr <<
" Result: " << match << endl;
257 cerr <<
"Expected " << nMatch <<
" matches but only found "
258 << (nMatch -
m_matches.size()) <<
"!" << endl;
270 boost::ignore_unused(pStderr);
273 std::istream &is =
m_useStderr ? pStderr : pStdout;
279 while (getline(is, line))
282 if (std::regex_match(line, matches,
m_regex))
285 ASSERTL0(matches.size() != 1,
"No test sections in regex!");
287 vector<MetricRegexFieldValue> okValues;
289 for (
int i = 1; i < matches.size(); ++i)
295 std::string(matches[i].first, matches[i].second);
296 okValues.push_back(okValue);
307 TiXmlElement *matches =
m_metric->FirstChildElement(
"matches");
311 "Couldn't remove matches from metric!");
315 matches =
new TiXmlElement(
"matches");
318 for (
int i = 0; i <
m_matches.size(); ++i)
320 TiXmlElement *match =
new TiXmlElement(
"match");
321 matches->LinkEndChild(match);
323 for (
int j = 0; j <
m_matches[i].size(); ++j)
325 TiXmlElement *
field =
new TiXmlElement(
"field");
326 match->LinkEndChild(
field);
328 field->SetAttribute(
"id", boost::lexical_cast<std::string>(j));
332 field->SetAttribute(
"tolerance",
333 boost::lexical_cast<std::string>(
#define ASSERTL0(condition, msg)
std::string RegisterCreatorFunction(std::string key, CreatorFunction func)
Base class for all metrics. Metric represents a test metric that can be used to evaluate the function...
TiXmlElement * m_metric
Pointer to XML structure containing metric definition.
std::string m_type
Stores the type of this metric (uppercase).
bool m_generate
Determines whether to generate this metric or not.
bool m_unordered
If true, regex matches may be in any order in output.
void v_Generate(std::istream &pStdout, std::istream &pStderr) override
Test output against a regex expression and set of matches.
MetricRegex(TiXmlElement *metric, bool generate)
Constructor.
std::vector< std::vector< MetricRegexFieldValue > > m_matches
Stores the multiple matches defined in each <MATCH> tag.
bool m_useStderr
If true, use stderr for testing/generation instead of stdout.
static MetricSharedPtr create(TiXmlElement *metric, bool generate)
std::regex m_regex
Storage for the boost regex.
bool v_Test(std::istream &pStdout, std::istream &pStderr) override
Test output against a regex expression and set of matches.
MetricFactory & GetMetricFactory()
scalarT< T > abs(scalarT< T > in)
Data structure for a Regex value to match.