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-2025 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>
24
25#include "InternalTest.h"
26#include "InternalTestStep.h"
27
28#ifdef _MSC_VER
29// disable using unsecure functions (getenv)
30#pragma warning(disable:4996)
31#endif
32
33// define number of points to interpolate
34#define numPointsInterpolation 100
35
36// ===========================================================================
37// member method definitions
38// ===========================================================================
39
40// ---------------------------------------------------------------------------
41// InternalTest::ViewPosition - public methods
42// ---------------------------------------------------------------------------
43
45
46
48 myX(x),
49 myY(y) {
50}
51
52
53InternalTest::ViewPosition::ViewPosition(const std::string& x, const std::string& y) :
54 myX(StringUtils::toInt(x)),
55 myY(StringUtils::toInt(y)) {
56}
57
58
59int
61 return myX;
62}
63
64
65int
67 return myY;
68}
69
70// ---------------------------------------------------------------------------
71// InternalTest::ContextualMenu - public methods
72// ---------------------------------------------------------------------------
73
75
76
77InternalTest::ContextualMenu::ContextualMenu(const std::string& mainMenuValue,
78 const std::string& subMenuAValue, const std::string& subMenuBValue) :
79 myMainMenu(StringUtils::toInt(mainMenuValue)),
80 mySubMenuA(StringUtils::toInt(subMenuAValue)),
81 mySubMenuB(StringUtils::toInt(subMenuBValue)) {
82}
83
84
85int
87 return myMainMenu;
88}
89
90
91int
93 return mySubMenuA;
94}
95
96
97int
99 return mySubMenuB;
100}
101
102// ---------------------------------------------------------------------------
103// InternalTest::Movement - public methods
104// ---------------------------------------------------------------------------
105
107
108
109InternalTest::Movement::Movement(const std::string& up, const std::string& down,
110 const std::string& left, const std::string& right) :
111 myUp(StringUtils::toInt(up)),
112 myDown(StringUtils::toInt(down)),
113 myLeft(StringUtils::toInt(left)),
114 myRight(StringUtils::toInt(right)) {
115}
116
117
118int
120 return myUp;
121}
122
123
124int
126 return myDown;
127}
128
129
130int
132 return myLeft;
133}
134
135
136int
138 return myRight;
139}
140
141// ---------------------------------------------------------------------------
142// InternalTest - public methods
143// ---------------------------------------------------------------------------
144
145InternalTest::InternalTest(const std::string& testFile) {
146 // locate sumo home directory
147 const auto sumoHome = std::string(getenv("SUMO_HOME"));
148 // load data files
149 myAttributesEnum = parseAttributesEnumFile(sumoHome + "/data/tests/attributesEnum.txt");
150 myContextualMenuOperations = parseContextualMenuOperationsFile(sumoHome + "/data/tests/contextualMenuOperations.txt");
151 myViewPositions = parseViewPositionsFile(sumoHome + "/data/tests/viewPositions.txt");
152 myMovements = parseMovementsFile(sumoHome + "/data/tests/movements.txt");
153 // open file
154 std::ifstream strm(testFile);
155 // check if file can be opened
156 if (!strm.good()) {
157 std::cout << "Could not open test file '" + testFile + "'." << std::endl;
158 throw ProcessError();
159 } else if (myAttributesEnum.empty() || myContextualMenuOperations.empty() || myViewPositions.empty() || myMovements.empty()) {
160 std::cout << "Error loading test data files" << std::endl;
161 throw ProcessError();
162 } else {
163 std::string line;
164 std::vector<std::pair<bool, std::string> > linesRaw;
165 // read full lines until end of file
166 while (std::getline(strm, line)) {
167 // filter lines
168 if (!line.empty() && // emty lines
169 !(line[0] == '#') && // comments
170 !startWith(line, "import") && // imports
171 !startWith(line, "time.") && // time calls
172 !startWith(line, "sys.")) { // sys calls
173 linesRaw.push_back(std::make_pair(startWith(line, "netedit."), line));
174 }
175 }
176 // clean lines
177 const auto lines = cleanLines(linesRaw);
178 // create steps
179 new InternalTestStep(this, "netedit.setupAndStart");
180 for (const auto& clearLine : lines) {
181 new InternalTestStep(this, clearLine);
182 }
183 new InternalTestStep(this, "netedit.finish");
184 }
185}
186
187
189 // delete all test steps
190 while (myInitialTestStep != nullptr) {
191 // store next step
192 auto nextStep = myInitialTestStep->getNextStep();
193 // delete current step
194 delete myInitialTestStep;
195 // set next step as initial step
196 myInitialTestStep = nextStep;
197 }
198}
199
200
201void
203 if (myLastTestStep == nullptr) {
204 // set initial step
205 myInitialTestStep = internalTestStep;
206 myLastTestStep = internalTestStep;
207 myCurrentTestStep = internalTestStep;
208 } else {
209 // set next step
210 myLastTestStep->setNextStep(internalTestStep);
211 myLastTestStep = internalTestStep;
212 }
213}
214
215
220
221
224 const auto currentStep = myCurrentTestStep;
226 return currentStep;
227}
228
229
230bool
232 return myRunning;
233}
234
235
236void
238 myRunning = false;
239}
240
241
242FXint
244 return static_cast<FXuint>(
245 std::chrono::duration_cast<std::chrono::milliseconds>(
246 std::chrono::steady_clock::now().time_since_epoch()
247 ).count());
248}
249
250
251const std::map<std::string, int>&
255
256
257const std::map<std::string, InternalTest::ContextualMenu>&
261
262
263const std::map<std::string, InternalTest::ViewPosition>&
267
268
269const std::map<std::string, InternalTest::Movement>&
271 return myMovements;
272}
273
274
279
280
281void
285
286
287std::vector<InternalTest::ViewPosition>
289 const int offsetStartX, const int offsetStartY,
290 const InternalTest::ViewPosition& viewEndPosition,
291 const int offsetEndX, const int offsetEndY) const {
292 // declare trajectory vector
293 std::vector<InternalTest::ViewPosition> trajectory;
294 trajectory.reserve(numPointsInterpolation);
295 // calulate from using offsets
296 const auto from = InternalTest::ViewPosition(viewStartPosition.getX() + offsetStartX, viewStartPosition.getY() + offsetStartY);
297 const auto to = InternalTest::ViewPosition(viewEndPosition.getX() + offsetEndX, viewEndPosition.getY() + offsetEndY);
298 // itearte over the number of points to interpolate
299 for (int i = 0; i < numPointsInterpolation; i++) {
300 const double t = static_cast<double>(i) / (numPointsInterpolation - 1); // t in [0, 1]
301 // calculate interpolated position
302 const int interpolatedX = int(from.getX() + t * (to.getX() - from.getX()));
303 const int interpolatedY = int(from.getY() + t * (to.getY() - from.getY()));
304 // add interpolated position
305 trajectory.push_back(ViewPosition(interpolatedX, interpolatedY));
306 }
307 return trajectory;
308}
309
310
311std::map<std::string, int>
312InternalTest::parseAttributesEnumFile(const std::string filePath) const {
313 std::map<std::string, int> solution;
314 // open file
315 std::ifstream strm(filePath);
316 // check if file can be opened
317 if (!strm.good()) {
318 WRITE_ERRORF(TL("Could not open attributes enum file '%'."), filePath);
319 } else {
320 std::string line;
321 // read full lines until end of file
322 while (std::getline(strm, line)) {
323 // use stringstream for
324 std::stringstream ss(line);
325 // read key and value
326 std::string key;
327 std::string value;
328 std::getline(ss, key, ' ');
329 std::getline(ss, value, '\n');
330 // check that int can be parsed
331 if (!StringUtils::isInt(value)) {
332 WRITE_ERRORF(TL("In internal test file, value '%' cannot be parsed to int."), value);
333 } else {
334 solution[key] = StringUtils::toInt(value);
335 }
336 }
337 }
338 return solution;
339}
340
341
342std::map<std::string, InternalTest::ContextualMenu>
343InternalTest::parseContextualMenuOperationsFile(const std::string filePath) const {
344 std::map<std::string, InternalTest::ContextualMenu> solution;
345 // open file
346 std::ifstream strm(filePath);
347 // check if file can be opened
348 if (!strm.good()) {
349 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
350 } else {
351 std::string line;
352 // read full lines until end of file
353 while (std::getline(strm, line)) {
354 // read key and value
355 std::string mainMenuKey;
356 std::string mainMenuValue;
357 std::string subMenuAKey;
358 std::string subMenuAValue;
359 std::string subMenuBKey;
360 std::string subMenuBValue;
361 // parse first line
362 std::stringstream mainMenuSS(line);
363 std::getline(mainMenuSS, mainMenuKey, ' ');
364 std::getline(mainMenuSS, mainMenuValue, '\n');
365 // parse second line
366 std::getline(strm, line);
367 std::stringstream subMenuASS(line);
368 std::getline(subMenuASS, subMenuAKey, ' ');
369 std::getline(subMenuASS, subMenuAValue, '\n');
370 // parse third line
371 std::getline(strm, line);
372 std::stringstream subMenuBSS(line);
373 std::getline(subMenuBSS, subMenuBKey, ' ');
374 std::getline(subMenuBSS, subMenuBValue, '\n');
375 // check that int can be parsed
376 if (!StringUtils::isInt(mainMenuValue)) {
377 WRITE_ERRORF(TL("In internal test file, mainMenu value '%' cannot be parsed to int."), mainMenuValue);
378 } else if (!StringUtils::isInt(subMenuAValue)) {
379 WRITE_ERRORF(TL("In internal test file, subMenuA value '%' cannot be parsed to int."), subMenuAValue);
380 } else if (!StringUtils::isInt(subMenuBValue)) {
381 WRITE_ERRORF(TL("In internal test file, subMenuB value '%' cannot be parsed to int."), subMenuBValue);
382 } else {
383 // remove '.mainMenuPosition' from mainMenuKey
384 solution[mainMenuKey.erase(mainMenuKey.size() - 17)] = InternalTest::ContextualMenu(mainMenuValue, subMenuAValue, subMenuBValue);
385 }
386 }
387 }
388 return solution;
389}
390
391
392std::map<std::string, InternalTest::ViewPosition>
393InternalTest::parseViewPositionsFile(const std::string filePath) const {
394 std::map<std::string, InternalTest::ViewPosition> solution;
395 // open file
396 std::ifstream strm(filePath);
397 // check if file can be opened
398 if (!strm.good()) {
399 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
400 } else {
401 std::string line;
402 // read full lines until end of file
403 while (std::getline(strm, line)) {
404 // use stringstream for
405 std::stringstream ss(line);
406 // read key and value
407 std::string key;
408 std::string xValue;
409 std::string yValue;
410 std::getline(ss, key, ' ');
411 std::getline(ss, xValue, ' ');
412 std::getline(ss, yValue, '\n');
413 // check that int can be parsed
414 if (!StringUtils::isInt(xValue)) {
415 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), xValue);
416 } else if (!StringUtils::isInt(yValue)) {
417 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), yValue);
418 } else {
419 solution[key] = InternalTest::ViewPosition(xValue, yValue);
420 }
421 }
422 }
423 return solution;
424}
425
426
427std::map<std::string, InternalTest::Movement>
428InternalTest::parseMovementsFile(const std::string filePath) const {
429 std::map<std::string, InternalTest::Movement> solution;
430 // open file
431 std::ifstream strm(filePath);
432 // check if file can be opened
433 if (!strm.good()) {
434 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
435 } else {
436 std::string line;
437 // read full lines until end of file
438 while (std::getline(strm, line)) {
439 // use stringstream for
440 std::stringstream ss(line);
441 // read key and value
442 std::string key;
443 std::string upValue;
444 std::string downValue;
445 std::string leftValue;
446 std::string rightValue;
447 std::getline(ss, key, ' ');
448 std::getline(ss, upValue, ' ');
449 std::getline(ss, downValue, ' ');
450 std::getline(ss, leftValue, ' ');
451 std::getline(ss, rightValue, '\n');
452 // check that int can be parsed
453 if (!StringUtils::isInt(upValue)) {
454 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), upValue);
455 } else if (!StringUtils::isInt(downValue)) {
456 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), downValue);
457 } else if (!StringUtils::isInt(leftValue)) {
458 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), leftValue);
459 } else if (!StringUtils::isInt(rightValue)) {
460 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), rightValue);
461 } else {
462 solution[key] = InternalTest::Movement(upValue, downValue, leftValue, rightValue);
463 }
464 }
465 }
466 return solution;
467}
468
469
470std::vector<std::string>
471InternalTest::cleanLines(const std::vector<std::pair<bool, std::string> >& linesRaw) const {
472 std::vector<std::string> results;
473 for (const auto& lineRaw : linesRaw) {
474 if (lineRaw.first) {
475 results.push_back(lineRaw.second);
476 } else if (results.size() > 0) {
477 results.back().append(lineRaw.second);
478 }
479 }
480 return results;
481}
482
483
484bool
485InternalTest::startWith(const std::string& str, const std::string& prefix) const {
486 if (prefix.size() > str.size()) {
487 return false;
488 } else {
489 for (int i = 0; i < (int)prefix.size(); i++) {
490 if (str[i] != prefix[i]) {
491 return false;
492 }
493 }
494 return true;
495 }
496}
497
498/****************************************************************************/
#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:40
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