Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
InternalTest.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// Class used for internal tests
19/****************************************************************************/
20#include <config.h>
21
22#include <fstream>
23#include <iostream>
25
26#include "InternalTest.h"
27#include "InternalTestStep.h"
28
29#ifdef _MSC_VER
30// disable using unsecure functions (getenv)
31#pragma warning(disable:4996)
32#endif
33
34// define number of points to interpolate
35#define numPointsInterpolation 100
36
37// ===========================================================================
38// member method definitions
39// ===========================================================================
40
41// ---------------------------------------------------------------------------
42// InternalTest::ViewPosition - public methods
43// ---------------------------------------------------------------------------
44
46
47
49 myX(x),
50 myY(y) {
51}
52
53
54InternalTest::ViewPosition::ViewPosition(const std::string& x, const std::string& y) :
55 myX(StringUtils::toInt(x)),
56 myY(StringUtils::toInt(y)) {
57}
58
59
60int
62 return myX;
63}
64
65
66int
68 return myY;
69}
70
71// ---------------------------------------------------------------------------
72// InternalTest::ContextualMenu - public methods
73// ---------------------------------------------------------------------------
74
76
77
78InternalTest::ContextualMenu::ContextualMenu(const std::string& mainMenuValue,
79 const std::string& subMenuAValue, const std::string& subMenuBValue) :
80 myMainMenu(StringUtils::toInt(mainMenuValue)),
81 mySubMenuA(StringUtils::toInt(subMenuAValue)),
82 mySubMenuB(StringUtils::toInt(subMenuBValue)) {
83}
84
85
86int
88 return myMainMenu;
89}
90
91
92int
94 return mySubMenuA;
95}
96
97
98int
100 return mySubMenuB;
101}
102
103// ---------------------------------------------------------------------------
104// InternalTest::Movement - public methods
105// ---------------------------------------------------------------------------
106
108
109
110InternalTest::Movement::Movement(const std::string& up, const std::string& down,
111 const std::string& left, const std::string& right) :
112 myUp(StringUtils::toInt(up)),
113 myDown(StringUtils::toInt(down)),
114 myLeft(StringUtils::toInt(left)),
115 myRight(StringUtils::toInt(right)) {
116}
117
118
119int
121 return myUp;
122}
123
124
125int
127 return myDown;
128}
129
130
131int
133 return myLeft;
134}
135
136
137int
139 return myRight;
140}
141
142// ---------------------------------------------------------------------------
143// InternalTest - public methods
144// ---------------------------------------------------------------------------
145
146InternalTest::InternalTest(const std::string& testFile) {
147 // locate sumo home directory
148 const auto sumoHome = std::string(getenv("SUMO_HOME"));
149 // load data files
150 myAttributesEnum = parseAttributesEnumFile(sumoHome + "/data/tests/attributesEnum.txt");
151 myContextualMenuOperations = parseContextualMenuOperationsFile(sumoHome + "/data/tests/contextualMenuOperations.txt");
152 myViewPositions = parseViewPositionsFile(sumoHome + "/data/tests/viewPositions.txt");
153 myMovements = parseMovementsFile(sumoHome + "/data/tests/movements.txt");
154 // open file
155 std::ifstream strm(testFile);
156 // check if file can be opened
157 if (!strm.good()) {
158 std::cout << "Could not open test file '" + testFile + "'." << std::endl;
159 throw ProcessError();
160 } else if (myAttributesEnum.empty() || myContextualMenuOperations.empty() || myViewPositions.empty() || myMovements.empty()) {
161 std::cout << "Error loading test data files" << std::endl;
162 throw ProcessError();
163 } else {
164 std::string line;
165 std::vector<std::pair<bool, std::string> > linesRaw;
166 // read full lines until end of file
167 while (std::getline(strm, line)) {
168 // filter lines
169 if (!line.empty() && // emty lines
170 !(line[0] == '#') && // comments
171 !startWith(line, "import") && // imports
172 !startWith(line, "time.") && // time calls
173 !startWith(line, "sys.")) { // sys calls
174 linesRaw.push_back(std::make_pair(startWith(line, "netedit."), line));
175 }
176 }
177 // clean lines
178 const auto lines = cleanLines(linesRaw);
179 // create steps
180 new InternalTestStep(this, "netedit.setupAndStart");
181 for (const auto& clearLine : lines) {
182 new InternalTestStep(this, clearLine);
183 }
184 new InternalTestStep(this, "netedit.finish");
185 }
186}
187
188
190 // delete all test steps
191 while (myInitialTestStep != nullptr) {
192 // store next step
193 auto nextStep = myInitialTestStep->getNextStep();
194 // delete current step
195 delete myInitialTestStep;
196 // set next step as initial step
197 myInitialTestStep = nextStep;
198 }
199}
200
201
202void
204 if (myLastTestStep == nullptr) {
205 // set initial step
206 myInitialTestStep = internalTestStep;
207 myLastTestStep = internalTestStep;
208 myCurrentTestStep = internalTestStep;
209 } else {
210 // set next step
211 myLastTestStep->setNextStep(internalTestStep);
212 myLastTestStep = internalTestStep;
213 }
214}
215
216
221
222
225 const auto currentStep = myCurrentTestStep;
227 return currentStep;
228}
229
230
231bool
233 return myRunning;
234}
235
236
237void
239 myRunning = false;
240}
241
242
243FXint
245 return static_cast<FXuint>(
246 std::chrono::duration_cast<std::chrono::milliseconds>(
247 std::chrono::steady_clock::now().time_since_epoch()
248 ).count());
249}
250
251
252const std::map<std::string, int>&
256
257
258const std::map<std::string, InternalTest::ContextualMenu>&
262
263
264const std::map<std::string, InternalTest::ViewPosition>&
268
269
270const std::map<std::string, InternalTest::Movement>&
272 return myMovements;
273}
274
275
280
281
282void
286
287
288std::vector<InternalTest::ViewPosition>
290 const int offsetStartX, const int offsetStartY,
291 const InternalTest::ViewPosition& viewEndPosition,
292 const int offsetEndX, const int offsetEndY) const {
293 // declare trajectory vector
294 std::vector<InternalTest::ViewPosition> trajectory;
295 trajectory.reserve(numPointsInterpolation);
296 // calulate from using offsets
297 const auto from = InternalTest::ViewPosition(viewStartPosition.getX() + offsetStartX, viewStartPosition.getY() + offsetStartY);
298 const auto to = InternalTest::ViewPosition(viewEndPosition.getX() + offsetEndX, viewEndPosition.getY() + offsetEndY);
299 // itearte over the number of points to interpolate
300 for (int i = 0; i < numPointsInterpolation; i++) {
301 const double t = static_cast<double>(i) / (numPointsInterpolation - 1); // t in [0, 1]
302 // calculate interpolated position
303 const int interpolatedX = int(from.getX() + t * (to.getX() - from.getX()));
304 const int interpolatedY = int(from.getY() + t * (to.getY() - from.getY()));
305 // add interpolated position
306 trajectory.push_back(ViewPosition(interpolatedX, interpolatedY));
307 }
308 return trajectory;
309}
310
311
312std::map<std::string, int>
313InternalTest::parseAttributesEnumFile(const std::string filePath) const {
314 std::map<std::string, int> solution;
315 // open file
316 std::ifstream strm(filePath);
317 // check if file can be opened
318 if (!strm.good()) {
319 WRITE_ERRORF(TL("Could not open attributes enum file '%'."), filePath);
320 } else {
321 std::string line;
322 // read full lines until end of file
323 while (std::getline(strm, line)) {
324 // use stringstream for
325 std::stringstream ss(line);
326 // read key and value
327 std::string key;
328 std::string value;
329 std::getline(ss, key, ' ');
330 std::getline(ss, value, '\n');
331 // check that int can be parsed
332 if (!StringUtils::isInt(value)) {
333 WRITE_ERRORF(TL("In internal test file, value '%' cannot be parsed to int."), value);
334 } else {
335 solution[key] = StringUtils::toInt(value);
336 }
337 }
338 }
339 return solution;
340}
341
342
343std::map<std::string, InternalTest::ContextualMenu>
344InternalTest::parseContextualMenuOperationsFile(const std::string filePath) const {
345 std::map<std::string, InternalTest::ContextualMenu> solution;
346 // open file
347 std::ifstream strm(filePath);
348 // check if file can be opened
349 if (!strm.good()) {
350 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
351 } else {
352 std::string line;
353 // read full lines until end of file
354 while (std::getline(strm, line)) {
355 // read key and value
356 std::string mainMenuKey;
357 std::string mainMenuValue;
358 std::string subMenuAKey;
359 std::string subMenuAValue;
360 std::string subMenuBKey;
361 std::string subMenuBValue;
362 // parse first line
363 std::stringstream mainMenuSS(line);
364 std::getline(mainMenuSS, mainMenuKey, ' ');
365 std::getline(mainMenuSS, mainMenuValue, '\n');
366 // parse second line
367 std::getline(strm, line);
368 std::stringstream subMenuASS(line);
369 std::getline(subMenuASS, subMenuAKey, ' ');
370 std::getline(subMenuASS, subMenuAValue, '\n');
371 // parse third line
372 std::getline(strm, line);
373 std::stringstream subMenuBSS(line);
374 std::getline(subMenuBSS, subMenuBKey, ' ');
375 std::getline(subMenuBSS, subMenuBValue, '\n');
376 // check that int can be parsed
377 if (!StringUtils::isInt(mainMenuValue)) {
378 WRITE_ERRORF(TL("In internal test file, mainMenu value '%' cannot be parsed to int."), mainMenuValue);
379 } else if (!StringUtils::isInt(subMenuAValue)) {
380 WRITE_ERRORF(TL("In internal test file, subMenuA value '%' cannot be parsed to int."), subMenuAValue);
381 } else if (!StringUtils::isInt(subMenuBValue)) {
382 WRITE_ERRORF(TL("In internal test file, subMenuB value '%' cannot be parsed to int."), subMenuBValue);
383 } else {
384 // remove '.mainMenuPosition' from mainMenuKey
385 solution[mainMenuKey.erase(mainMenuKey.size() - 17)] = InternalTest::ContextualMenu(mainMenuValue, subMenuAValue, subMenuBValue);
386 }
387 }
388 }
389 return solution;
390}
391
392
393std::map<std::string, InternalTest::ViewPosition>
394InternalTest::parseViewPositionsFile(const std::string filePath) const {
395 std::map<std::string, InternalTest::ViewPosition> solution;
396 // open file
397 std::ifstream strm(filePath);
398 // check if file can be opened
399 if (!strm.good()) {
400 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
401 } else {
402 std::string line;
403 // read full lines until end of file
404 while (std::getline(strm, line)) {
405 // use stringstream for
406 std::stringstream ss(line);
407 // read key and value
408 std::string key;
409 std::string xValue;
410 std::string yValue;
411 std::getline(ss, key, ' ');
412 std::getline(ss, xValue, ' ');
413 std::getline(ss, yValue, '\n');
414 // check that int can be parsed
415 if (!StringUtils::isInt(xValue)) {
416 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), xValue);
417 } else if (!StringUtils::isInt(yValue)) {
418 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), yValue);
419 } else {
420 solution[key] = InternalTest::ViewPosition(xValue, yValue);
421 }
422 }
423 }
424 return solution;
425}
426
427
428std::map<std::string, InternalTest::Movement>
429InternalTest::parseMovementsFile(const std::string filePath) const {
430 std::map<std::string, InternalTest::Movement> solution;
431 // open file
432 std::ifstream strm(filePath);
433 // check if file can be opened
434 if (!strm.good()) {
435 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
436 } else {
437 std::string line;
438 // read full lines until end of file
439 while (std::getline(strm, line)) {
440 // use stringstream for
441 std::stringstream ss(line);
442 // read key and value
443 std::string key;
444 std::string upValue;
445 std::string downValue;
446 std::string leftValue;
447 std::string rightValue;
448 std::getline(ss, key, ' ');
449 std::getline(ss, upValue, ' ');
450 std::getline(ss, downValue, ' ');
451 std::getline(ss, leftValue, ' ');
452 std::getline(ss, rightValue, '\n');
453 // check that int can be parsed
454 if (!StringUtils::isInt(upValue)) {
455 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), upValue);
456 } else if (!StringUtils::isInt(downValue)) {
457 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), downValue);
458 } else if (!StringUtils::isInt(leftValue)) {
459 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), leftValue);
460 } else if (!StringUtils::isInt(rightValue)) {
461 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), rightValue);
462 } else {
463 solution[key] = InternalTest::Movement(upValue, downValue, leftValue, rightValue);
464 }
465 }
466 }
467 return solution;
468}
469
470
471std::vector<std::string>
472InternalTest::cleanLines(const std::vector<std::pair<bool, std::string> >& linesRaw) const {
473 std::vector<std::string> results;
474 for (const auto& lineRaw : linesRaw) {
475 if (lineRaw.first) {
476 results.push_back(lineRaw.second);
477 } else if (results.size() > 0) {
478 results.back().append(lineRaw.second);
479 }
480 }
481 return results;
482}
483
484
485bool
486InternalTest::startWith(const std::string& str, const std::string& prefix) const {
487 if (prefix.size() > str.size()) {
488 return false;
489 } else {
490 for (int i = 0; i < (int)prefix.size(); i++) {
491 if (str[i] != prefix[i]) {
492 return false;
493 }
494 }
495 return true;
496 }
497}
498
499/****************************************************************************/
#define numPointsInterpolation
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define TL(string)
Definition MsgHandler.h:304
int getUp() const
get up value
int getLeft() const
get left value
int getDown() const
get down value
Movement()
default constructor
int getRight() const
get right value
int getY() const
get y value
int getX() const
get x value
ViewPosition()
default constructor
std::vector< InternalTest::ViewPosition > interpolateViewPositions(const InternalTest::ViewPosition &viewStartPosition, const int offsetStartX, const int offsetStartY, const InternalTest::ViewPosition &viewEndPosition, const int offsetEndX, const int offsetEndY) const
interpolate view positions
bool isRunning() const
check if test is running
void addTestSteps(InternalTestStep *internalTestStep)
add test steps
InternalTestStep * getCurrentStep() const
get current step
const std::map< std::string, InternalTest::ContextualMenu > & getContextualMenuOperations() const
get map with contextual menu operation jump steps
bool startWith(const std::string &str, const std::string &prefix) const
check if the given string start with
std::vector< std::string > cleanLines(const std::vector< std::pair< bool, std::string > > &linesRaw) const
clear lines
const std::map< std::string, int > & getAttributesEnum() const
get map with attributesEnum jump steps
InternalTest::ViewPosition myLastMovedPosition
last moved position
InternalTestStep * myLastTestStep
last test steps
InternalTestStep * myCurrentTestStep
current test step
std::map< std::string, int > parseAttributesEnumFile(const std::string filePath) const
parse attributesEnum file
std::map< std::string, InternalTest::ViewPosition > parseViewPositionsFile(const std::string filePath) const
parse viewPositions file
~InternalTest()
destructor
std::map< std::string, InternalTest::Movement > myMovements
vector with movements
std::map< std::string, InternalTest::ContextualMenu > myContextualMenuOperations
vector with contextual menu operation jump steps
std::map< std::string, InternalTest::ContextualMenu > parseContextualMenuOperationsFile(const std::string filePath) const
parse attributesEnum file
bool myRunning
flag to indicate if test is running
std::map< std::string, InternalTest::ViewPosition > myViewPositions
vector with view positions
std::map< std::string, int > myAttributesEnum
vector with attributesEnum jump steps
std::map< std::string, InternalTest::Movement > parseMovementsFile(const std::string filePath) const
parse movements file
const std::map< std::string, InternalTest::ViewPosition > & getViewPositions() const
get map with view position pairs
InternalTest()=delete
invalidate default constructor
void stopTests()
stop tests
FXint getTime() const
get currentTime
void updateLastMovedPosition(const int x, const int y)
update last moved position
InternalTestStep * setNextStep()
get current step and set next step
const InternalTest::ViewPosition & getLastMovedPosition() const
get last moved position
InternalTestStep * myInitialTestStep
initial test steps
const std::map< std::string, InternalTest::Movement > & getMovements() const
get map with movement pairs
InternalTestStep * getNextStep() const
get next step
void setNextStep(InternalTestStep *nextStep)
set next step
Some static methods for string processing.
Definition StringUtils.h:39
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool isInt(const std::string &sData)
check if the given sData can be converted to int
int getSubMenuBPosition() const
get submenu B position
int getMainMenuPosition() const
get main menu position
ContextualMenu()
default constructor
int getSubMenuAPosition() const
get submenu A position