LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
TestCaseProcessor.cpp
Go to the documentation of this file.
1// Copyright 2002-2022 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
14
16
17#include <sstream>
18#include <fstream>
19#include <algorithm>
20#include <iterator>
21
22#include <QtCore/QStringList>
23#include <QtCore/QFile>
24
25std::ostream& operator<<(std::ostream& oss, const QStringList& qsl)
26{
27 oss << "{";
28 Q_FOREACH(QString s, qsl)
29 {
30 oss << s.toUtf8().data() << ",";
31 }
32 oss << "}";
33 return oss;
34}
35
36namespace Lima
37{
38namespace Common
39{
40namespace TGV
41{
42
44{
45 friend class TestCaseProcessor;
46public:
47
48 TestCaseProcessorPrivate( const std::string workingDirectory );
50
52
53 static QStringList evaluateExpression(
54 const std::string& expr,
55 pugi::xml_node& node);
56//
57 static bool existsExpression(
58 const std::string& expr,
59 pugi::xml_node& node);
60
61};
62
63TestCaseProcessorPrivate::TestCaseProcessorPrivate(const std::string workingDirectory) :
64 m_workingDirectory(QString::fromStdString(workingDirectory))
65{
66}
67
68TestCaseProcessor::TestCaseProcessor(const std::string workingDirectory) :
69 m_d(new TestCaseProcessorPrivate(workingDirectory))
70{
71}
72
74 const TestCase& testCase, const std::string& pipeName,
75 const std::string& textFile, const std::string& traceFilePrefix ) const
76{
77 LIMA_UNUSED(textFile);
79 // Valid TestUnits
80 for (const auto& test: testCase.tests)
81 {
82 std::string traceFile(traceFilePrefix+test.trace);
83
84 /* Load XML document */
86
87 LTRACE << "TestCaseProcessor::evalTestCase load trace file" << traceFile;
88 pugi::xml_parse_result result = doc.load_file(traceFile.c_str());
89
90 if (!result)
91 {
92 LERROR << "Error: Unable to parse output file " << traceFile << ":" << result.description();
94 "Error: Unable to parse output file !", pipeName, test);
95 }
96
97 // OK, let's evaluate the expression...
98 // Check unary operators before evaluate se right member
99 LTRACE << "TestCaseProcessor::evalTestCase test:" << test.left << test.op << test.right;
100 if (test.op=="notexists")
101 {
102 if (m_d->existsExpression(test.left, doc))
103 {
104 return TestCaseError(testCase, TestCaseError::TestCaseFailed,"an element exists !", pipeName, test);
105 }
106 }
107 else if (test.op=="exists")
108 {
109 if (!m_d->existsExpression(test.left, doc))
110 {
111 std::ostringstream oss;
112 oss << "element doesn't exist ! : " << test.left;
113 return TestCaseError(testCase, TestCaseError::TestCaseFailed,oss.str(), pipeName, test);
114 }
115 }
116 else
117 {
118
119 // operator is a binary one. evaluate the second expression
120 QStringList left = m_d->evaluateExpression(test.left, doc);
121 left.removeDuplicates();
122 QStringList right = m_d->evaluateExpression(test.right, doc);
123 right.removeDuplicates();
124
125 QSet<QString> sleft;
126
127 Q_FOREACH (QString element, left)
128 {
129 sleft.insert(element);
130 }
131 QSet<QString> sright;
132 Q_FOREACH (QString element, right)
133 {
134 sright.insert(element);
135 }
136
137 if (test.op=="=")
138 {
139 if (sleft!=sright)
140 {
141 std::ostringstream oss;
142 oss << "equality check failed : " << left << " != " << right << std::endl;
143 oss << " left : " << test.left << std::endl;
144 oss << " right: " << test.right;
145
146 return TestCaseError(testCase, TestCaseError::TestCaseFailed, oss.str(), pipeName, test);
147 }
148 else if (left.size()==0)
149 {
150 std::ostringstream oss;
151 oss << "left and right member are empty !";
152 return TestCaseError(testCase, TestCaseError::TestCaseFailed,oss.str(), pipeName, test);
153 }
154 }
155 else if (test.op=="!=")
156 {
157 if (sleft==sright)
158 {
159 std::ostringstream oss;
160 oss << "inequality check failed : " << left << " == " << right << std::endl;
161 oss << " left : " << test.left << std::endl;
162 oss << " right: " << test.right;
163 return TestCaseError(testCase, TestCaseError::TestCaseFailed,oss.str(), pipeName, test);
164 }
165 }
166 else if (test.op=="contains")
167 {
168 Q_FOREACH(QString s, sright)
169 {
170 if (!sleft.contains(s))
171 {
172 std::ostringstream oss;
173 oss << "includes check failed : " << left << " not contains " << right << std::endl;
174 oss << " left : " << test.left << std::endl;
175 oss << " right: " << test.right;
176 return TestCaseError(testCase, TestCaseError::TestCaseFailed,oss.str(), pipeName, test);
177 }
178 }
179 }
180 else if (test.op=="notcontains")
181 {
182 Q_FOREACH(QString s, sleft)
183 {
184 if (!sright.contains(s))
185 {
186 std::ostringstream oss;
187 oss << "not includes check failed : " << left << " contains " << right;
188 return TestCaseError(testCase, TestCaseError::TestCaseFailed,oss.str(), pipeName, test);
189 }
190 }
191 }
192 else if (test.op=="distinct")
193 {
194 Q_FOREACH(QString l, sleft)
195 {
196 Q_FOREACH(QString r, sright)
197 {
198 if (l==r)
199 {
200 std::ostringstream oss;
201 oss << l.toUtf8().data() << " is a common value of the two sets that should be disctinct !" << std::endl;
202 oss << " left : " << test.left << std::endl;
203 oss << " right: " << test.right;
204 return TestCaseError(testCase, TestCaseError::TestCaseFailed,oss.str(), pipeName, test);
205 }
206 }
207 }
208 }
209 else if (test.op=="intersect")
210 {
211 Q_FOREACH(QString l, sleft)
212 {
213 Q_FOREACH(QString r, sright)
214 {
215 if (l==r)
216 {
217 return TestCaseError(testCase, TestCaseError::NoError, "", pipeName, test);
218 }
219 }
220 }
221 std::ostringstream oss;
222 oss << "intersect failed : no common value between " << left << " and " << right << " !" << std::endl;
223 oss << " left : " << test.left << std::endl;
224 oss << " right: " << test.right;
225 return TestCaseError(testCase, TestCaseError::TestCaseFailed,oss.str(), pipeName, test);
226 }
227 else if ((test.op!="exists") && (test.op!="notexists"))
228 {
229 return TestCaseError(testCase, TestCaseError::InvalidOperator, (test).id, pipeName, test);
230 }
231 }
232 }
233 return TestCaseError(testCase, "", pipeName);
234}
235
237 const std::string& expr,
238 pugi::xml_node& node)
239{
241 QStringList results;
242
243 if (expr.substr(0,6)=="XPATH#")
244 {
245 /* Evaluate xpath expression */
246 QString xpath = QString::fromUtf8(expr.substr(6).c_str());//+"/string()";
247 LDEBUG << "TestCaseProcessor::evaluateExpression setQuery("<<xpath<<");";
248 auto xnodes = node.select_nodes(xpath.toUtf8().data());
249 LDEBUG << "TestCaseProcessor::evaluateExpression nb nodes selected:" << xnodes.size();
250 for (const auto& node: xnodes)
251 {
252 if (node.attribute())
253 {
254 LDEBUG << "TestCaseProcessor::evaluateExpression result is an attribute with value:" << node.attribute().value();
255 results.push_back(QString::fromUtf8(node.attribute().value()));
256 }
257 else if (node.node())
258 {
259 LDEBUG << "TestCaseProcessor::evaluateExpression result is a node with text:" << node.node().text().as_string();
260 results.push_back(QString::fromUtf8(node.node().text().as_string()));
261 }
262 }
263 LDEBUG << "TestCaseProcessor::evaluateExpression evaluates to " << results;
264 }
265 else if (expr.substr(0,4)=="SET#")
266 {
267 size_t start=4;
268 while (start<expr.size())
269 {
270 size_t end=expr.find('#',start);
271 if (end==std::string::npos)
272 {
273 end=expr.size();
274 }
275 std::string val=expr.substr(start,end-start);
276 results.push_back(QString::fromUtf8(val.c_str()));
277 start=end+1;
278 }
279 }
280 else
281 {
282 results.push_back(QString::fromUtf8(expr.c_str()));
283 }
284 return results;
285}
286
288 const std::string& expr,
289 pugi::xml_node& node)
290{
291// TGVLOGINIT;
292 return !evaluateExpression(expr,node).empty();
293}
294
296{
297 return m_d->m_workingDirectory;
298}
299
300} // TGV
301} // Common
302} // Lima
#define LTRACE
Definition LimaCommon.h:156
#define TGVLOGINIT
Definition LimaCommon.h:216
#define LIMA_UNUSED(x)
Definition LimaCommon.h:224
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
std::ostream & operator<<(std::ostream &oss, const QStringList &qsl)
static QStringList evaluateExpression(const std::string &expr, pugi::xml_node &node)
static bool existsExpression(const std::string &expr, pugi::xml_node &node)
TestCaseProcessorPrivate(const std::string workingDirectory)
TestCaseProcessor(const std::string workingDirectory)
TestCaseError evalTestCase(const TestCase &testCase, const std::string &pipeName, const std::string &textFile, const std::string &traceFilePrefix) const
const char_t * value() const
Definition pugixml.cpp:5248
xml_parse_result load_file(const char *path, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition pugixml.cpp:7207
xml_text text() const
Definition pugixml.cpp:5634
xml_attribute attribute(const char_t *name) const
Definition pugixml.cpp:5547
xpath_node_set select_nodes(const char_t *query, xpath_variable_set *variables=PUGIXML_NULL) const
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition pugixml.cpp:6484
size_t size() const
NAUTITIA.
std::list< TestUnit > tests
Definition TestCase.h:68
const char * description() const
Definition pugixml.cpp:6908