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 // ignore comments (#) and all lines that doesn't start with netedit.
168 if (!line.empty() && (line[0] != '#')) {
169 linesRaw.push_back(std::make_pair(startWith(line, "netedit."), line));
170 }
171 }
172 // clean lines
173 const auto lines = cleanLines(linesRaw);
174 // create steps
175 new InternalTestStep(this, "netedit.setupAndStart");
176 for (const auto& clearLine : lines) {
177 new InternalTestStep(this, clearLine);
178 }
179 }
180}
181
182
184 for (auto testStep : myTestSteps) {
185 delete testStep;
186 }
187}
188
189
190FXint
192 return static_cast<FXuint>(
193 std::chrono::duration_cast<std::chrono::milliseconds>(
194 std::chrono::steady_clock::now().time_since_epoch()
195 ).count());
196}
197
198
199void
201 myTestSteps.push_back(internalTestStep);
202}
203
204
207 if (myCurrentStep < myTestSteps.size()) {
208 return myTestSteps.at(myCurrentStep);
209 } else {
210 return nullptr;
211 }
212}
213
214
217 if (myTestSteps.empty()) {
218 return nullptr;
219 } else {
220 return myTestSteps.back();
221 }
222}
223
224
225const std::map<std::string, int>&
229
230
231const std::map<std::string, InternalTest::ContextualMenu>&
235
236
237const std::map<std::string, InternalTest::ViewPosition>&
241
242
243const std::map<std::string, InternalTest::Movement>&
245 return myMovements;
246}
247
248
253
254
255void
259
260
261std::vector<InternalTest::ViewPosition>
263 const int offsetStartX, const int offsetStartY,
264 const InternalTest::ViewPosition& viewEndPosition,
265 const int offsetEndX, const int offsetEndY) const {
266 // declare trajectory vector
267 std::vector<InternalTest::ViewPosition> trajectory;
268 trajectory.reserve(numPointsInterpolation);
269 // calulate from using offsets
270 const auto from = InternalTest::ViewPosition(viewStartPosition.getX() + offsetStartX, viewStartPosition.getY() + offsetStartY);
271 const auto to = InternalTest::ViewPosition(viewEndPosition.getX() + offsetEndX, viewEndPosition.getY() + offsetEndY);
272 // itearte over the number of points to interpolate
273 for (int i = 0; i < numPointsInterpolation; i++) {
274 const double t = static_cast<double>(i) / (numPointsInterpolation - 1); // t in [0, 1]
275 // calculate interpolated position
276 const int interpolatedX = int(from.getX() + t * (to.getX() - from.getX()));
277 const int interpolatedY = int(from.getY() + t * (to.getY() - from.getY()));
278 // add interpolated position
279 trajectory.push_back(ViewPosition(interpolatedX, interpolatedY));
280 }
281 return trajectory;
282}
283
284
285std::map<std::string, int>
286InternalTest::parseAttributesEnumFile(const std::string filePath) const {
287 std::map<std::string, int> solution;
288 // open file
289 std::ifstream strm(filePath);
290 // check if file can be opened
291 if (!strm.good()) {
292 WRITE_ERRORF(TL("Could not open attributes enum file '%'."), filePath);
293 } else {
294 std::string line;
295 // read full lines until end of file
296 while (std::getline(strm, line)) {
297 // use stringstream for
298 std::stringstream ss(line);
299 // read key and value
300 std::string key;
301 std::string value;
302 std::getline(ss, key, ' ');
303 std::getline(ss, value, '\n');
304 // check that int can be parsed
305 if (!StringUtils::isInt(value)) {
306 WRITE_ERRORF(TL("In internal test file, value '%' cannot be parsed to int."), value);
307 } else {
308 solution[key] = StringUtils::toInt(value);
309 }
310 }
311 }
312 return solution;
313}
314
315
316std::map<std::string, InternalTest::ContextualMenu>
317InternalTest::parseContextualMenuOperationsFile(const std::string filePath) const {
318 std::map<std::string, InternalTest::ContextualMenu> solution;
319 // open file
320 std::ifstream strm(filePath);
321 // check if file can be opened
322 if (!strm.good()) {
323 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
324 } else {
325 std::string line;
326 // read full lines until end of file
327 while (std::getline(strm, line)) {
328 // read key and value
329 std::string mainMenuKey;
330 std::string mainMenuValue;
331 std::string subMenuAKey;
332 std::string subMenuAValue;
333 std::string subMenuBKey;
334 std::string subMenuBValue;
335 // parse first line
336 std::stringstream mainMenuSS(line);
337 std::getline(mainMenuSS, mainMenuKey, ' ');
338 std::getline(mainMenuSS, mainMenuValue, '\n');
339 // parse second line
340 std::getline(strm, line);
341 std::stringstream subMenuASS(line);
342 std::getline(subMenuASS, subMenuAKey, ' ');
343 std::getline(subMenuASS, subMenuAValue, '\n');
344 // parse third line
345 std::getline(strm, line);
346 std::stringstream subMenuBSS(line);
347 std::getline(subMenuBSS, subMenuBKey, ' ');
348 std::getline(subMenuBSS, subMenuBValue, '\n');
349 // check that int can be parsed
350 if (!StringUtils::isInt(mainMenuValue)) {
351 WRITE_ERRORF(TL("In internal test file, mainMenu value '%' cannot be parsed to int."), mainMenuValue);
352 } else if (!StringUtils::isInt(subMenuAValue)) {
353 WRITE_ERRORF(TL("In internal test file, subMenuA value '%' cannot be parsed to int."), subMenuAValue);
354 } else if (!StringUtils::isInt(subMenuBValue)) {
355 WRITE_ERRORF(TL("In internal test file, subMenuB value '%' cannot be parsed to int."), subMenuBValue);
356 } else {
357 // remove '.mainMenuPosition' from mainMenuKey
358 solution[mainMenuKey.erase(mainMenuKey.size() - 17)] = InternalTest::ContextualMenu(mainMenuValue, subMenuAValue, subMenuBValue);
359 }
360 }
361 }
362 return solution;
363}
364
365
366std::map<std::string, InternalTest::ViewPosition>
367InternalTest::parseViewPositionsFile(const std::string filePath) const {
368 std::map<std::string, InternalTest::ViewPosition> solution;
369 // open file
370 std::ifstream strm(filePath);
371 // check if file can be opened
372 if (!strm.good()) {
373 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
374 } else {
375 std::string line;
376 // read full lines until end of file
377 while (std::getline(strm, line)) {
378 // use stringstream for
379 std::stringstream ss(line);
380 // read key and value
381 std::string key;
382 std::string xValue;
383 std::string yValue;
384 std::getline(ss, key, ' ');
385 std::getline(ss, xValue, ' ');
386 std::getline(ss, yValue, '\n');
387 // check that int can be parsed
388 if (!StringUtils::isInt(xValue)) {
389 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), xValue);
390 } else if (!StringUtils::isInt(yValue)) {
391 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), yValue);
392 } else {
393 solution[key] = InternalTest::ViewPosition(xValue, yValue);
394 }
395 }
396 }
397 return solution;
398}
399
400
401std::map<std::string, InternalTest::Movement>
402InternalTest::parseMovementsFile(const std::string filePath) const {
403 std::map<std::string, InternalTest::Movement> solution;
404 // open file
405 std::ifstream strm(filePath);
406 // check if file can be opened
407 if (!strm.good()) {
408 WRITE_ERRORF(TL("Could not open view positions file '%'."), filePath);
409 } else {
410 std::string line;
411 // read full lines until end of file
412 while (std::getline(strm, line)) {
413 // use stringstream for
414 std::stringstream ss(line);
415 // read key and value
416 std::string key;
417 std::string upValue;
418 std::string downValue;
419 std::string leftValue;
420 std::string rightValue;
421 std::getline(ss, key, ' ');
422 std::getline(ss, upValue, ' ');
423 std::getline(ss, downValue, ' ');
424 std::getline(ss, leftValue, ' ');
425 std::getline(ss, rightValue, '\n');
426 // check that int can be parsed
427 if (!StringUtils::isInt(upValue)) {
428 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), upValue);
429 } else if (!StringUtils::isInt(downValue)) {
430 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), downValue);
431 } else if (!StringUtils::isInt(leftValue)) {
432 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), leftValue);
433 } else if (!StringUtils::isInt(rightValue)) {
434 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), rightValue);
435 } else {
436 solution[key] = InternalTest::Movement(upValue, downValue, leftValue, rightValue);
437 }
438 }
439 }
440 return solution;
441}
442
443
444std::vector<std::string>
445InternalTest::cleanLines(const std::vector<std::pair<bool, std::string> >& linesRaw) const {
446 std::vector<std::string> results;
447 for (const auto& lineRaw : linesRaw) {
448 if (lineRaw.first) {
449 results.push_back(lineRaw.second);
450 } else if (results.size() > 0) {
451 results.back().append(lineRaw.second);
452 }
453 }
454 return results;
455}
456
457
458bool
459InternalTest::startWith(const std::string& str, const std::string& prefix) const {
460 if (prefix.size() > str.size()) {
461 return false;
462 } else {
463 for (int i = 0; i < (int)prefix.size(); i++) {
464 if (str[i] != prefix[i]) {
465 return false;
466 }
467 }
468 return true;
469 }
470}
471
472/****************************************************************************/
#define numPointsInterpolation
#define WRITE_ERRORF(...)
Definition MsgHandler.h:297
#define TL(string)
Definition MsgHandler.h:305
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
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
std::map< std::string, int > parseAttributesEnumFile(const std::string filePath) const
parse attributesEnum file
std::vector< InternalTestStep * > myTestSteps
test steps
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
size_t myCurrentStep
current step index
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
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
FXint getTime() const
get currentTime
void updateLastMovedPosition(const int x, const int y)
update last moved position
const InternalTest::ViewPosition & getLastMovedPosition() const
get last moved position
InternalTestStep * getLastTestStep() const
get last test step
const std::map< std::string, InternalTest::Movement > & getMovements() const
get map with movement pairs
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