LCOV - code coverage report
Current view: top level - src/utils/tests - InternalTest.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 0.0 % 211 0
Test Date: 2026-03-02 16:00:03 Functions: 0.0 % 38 0

            Line data    Source code
       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              : /****************************************************************************/
      14              : /// @file    InternalTest.cpp
      15              : /// @author  Pablo Alvarez Lopez
      16              : /// @date    Mar 2025
      17              : ///
      18              : // Class used for internal tests
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <fstream>
      23              : #include <utils/common/MsgHandler.h>
      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              : 
      44            0 : InternalTest::ViewPosition::ViewPosition() {}
      45              : 
      46              : 
      47            0 : InternalTest::ViewPosition::ViewPosition(const int x, const int y) :
      48            0 :     myX(x),
      49            0 :     myY(y) {
      50            0 : }
      51              : 
      52              : 
      53            0 : InternalTest::ViewPosition::ViewPosition(const std::string& x, const std::string& y) :
      54            0 :     myX(StringUtils::toInt(x)),
      55            0 :     myY(StringUtils::toInt(y)) {
      56            0 : }
      57              : 
      58              : 
      59              : int
      60            0 : InternalTest::ViewPosition::getX() const {
      61            0 :     return myX;
      62              : }
      63              : 
      64              : 
      65              : int
      66            0 : InternalTest::ViewPosition::getY() const {
      67            0 :     return myY;
      68              : }
      69              : 
      70              : // ---------------------------------------------------------------------------
      71              : // InternalTest::ContextualMenu - public methods
      72              : // ---------------------------------------------------------------------------
      73              : 
      74            0 : InternalTest::ContextualMenu::ContextualMenu() {}
      75              : 
      76              : 
      77            0 : InternalTest::ContextualMenu::ContextualMenu(const std::string& mainMenuValue,
      78            0 :         const std::string& subMenuAValue, const std::string& subMenuBValue) :
      79            0 :     myMainMenu(StringUtils::toInt(mainMenuValue)),
      80            0 :     mySubMenuA(StringUtils::toInt(subMenuAValue)),
      81            0 :     mySubMenuB(StringUtils::toInt(subMenuBValue)) {
      82            0 : }
      83              : 
      84              : 
      85              : int
      86            0 : InternalTest::ContextualMenu::getMainMenuPosition() const {
      87            0 :     return myMainMenu;
      88              : }
      89              : 
      90              : 
      91              : int
      92            0 : InternalTest::ContextualMenu::getSubMenuAPosition() const {
      93            0 :     return mySubMenuA;
      94              : }
      95              : 
      96              : 
      97              : int
      98            0 : InternalTest::ContextualMenu::getSubMenuBPosition() const {
      99            0 :     return mySubMenuB;
     100              : }
     101              : 
     102              : // ---------------------------------------------------------------------------
     103              : // InternalTest::Movement - public methods
     104              : // ---------------------------------------------------------------------------
     105              : 
     106            0 : InternalTest::Movement::Movement() {}
     107              : 
     108              : 
     109            0 : InternalTest::Movement::Movement(const std::string& up, const std::string& down,
     110            0 :                                  const std::string& left, const std::string& right) :
     111            0 :     myUp(StringUtils::toInt(up)),
     112            0 :     myDown(StringUtils::toInt(down)),
     113            0 :     myLeft(StringUtils::toInt(left)),
     114            0 :     myRight(StringUtils::toInt(right)) {
     115            0 : }
     116              : 
     117              : 
     118              : int
     119            0 : InternalTest::Movement::getUp() const {
     120            0 :     return myUp;
     121              : }
     122              : 
     123              : 
     124              : int
     125            0 : InternalTest::Movement::getDown() const {
     126            0 :     return myDown;
     127              : }
     128              : 
     129              : 
     130              : int
     131            0 : InternalTest::Movement::getLeft() const {
     132            0 :     return myLeft;
     133              : }
     134              : 
     135              : 
     136              : int
     137            0 : InternalTest::Movement::getRight() const {
     138            0 :     return myRight;
     139              : }
     140              : 
     141              : // ---------------------------------------------------------------------------
     142              : // InternalTest - public methods
     143              : // ---------------------------------------------------------------------------
     144              : 
     145            0 : InternalTest::InternalTest(const std::string& testFile) {
     146              :     // locate sumo home directory
     147            0 :     const auto sumoHome = std::string(getenv("SUMO_HOME"));
     148              :     // load data files
     149            0 :     myAttributesEnum = parseAttributesEnumFile(sumoHome + "/data/tests/attributesEnum.txt");
     150            0 :     myContextualMenuOperations = parseContextualMenuOperationsFile(sumoHome + "/data/tests/contextualMenuOperations.txt");
     151            0 :     myViewPositions = parseViewPositionsFile(sumoHome + "/data/tests/viewPositions.txt");
     152            0 :     myMovements = parseMovementsFile(sumoHome + "/data/tests/movements.txt");
     153              :     // open file
     154            0 :     std::ifstream strm(testFile);
     155              :     // check if file can be opened
     156            0 :     if (!strm.good()) {
     157            0 :         std::cout << "Could not open test file '" + testFile + "'." << std::endl;
     158            0 :         throw ProcessError();
     159            0 :     } else if (myAttributesEnum.empty() || myContextualMenuOperations.empty() || myViewPositions.empty() || myMovements.empty()) {
     160              :         std::cout << "Error loading test data files" << std::endl;
     161            0 :         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            0 :         while (std::getline(strm, line)) {
     167              :             // filter lines
     168            0 :             if (!line.empty() &&                // emty lines
     169            0 :                     !(line[0] == '#') &&            // comments
     170            0 :                     !startWith(line, "import") &&   // imports
     171            0 :                     !startWith(line, "time.") &&    // time calls
     172            0 :                     !startWith(line, "sys.")) {     // sys calls
     173            0 :                 linesRaw.push_back(std::make_pair(startWith(line, "netedit."), line));
     174              :             }
     175              :         }
     176              :         // clean lines
     177            0 :         const auto lines = cleanLines(linesRaw);
     178              :         // create steps
     179            0 :         new InternalTestStep(this, "netedit.setupAndStart");
     180            0 :         for (const auto& clearLine : lines) {
     181            0 :             new InternalTestStep(this, clearLine);
     182              :         }
     183            0 :         new InternalTestStep(this, "netedit.finish");
     184            0 :     }
     185            0 : }
     186              : 
     187              : 
     188            0 : InternalTest::~InternalTest() {
     189              :     // delete all test steps
     190            0 :     while (myInitialTestStep != nullptr) {
     191              :         // store next step
     192            0 :         auto nextStep = myInitialTestStep->getNextStep();
     193              :         // delete current step
     194            0 :         delete myInitialTestStep;
     195              :         // set next step as initial step
     196            0 :         myInitialTestStep = nextStep;
     197              :     }
     198            0 : }
     199              : 
     200              : 
     201              : void
     202            0 : InternalTest::addTestSteps(InternalTestStep* internalTestStep) {
     203            0 :     if (myLastTestStep == nullptr) {
     204              :         // set initial step
     205            0 :         myInitialTestStep = internalTestStep;
     206            0 :         myLastTestStep = internalTestStep;
     207            0 :         myCurrentTestStep = internalTestStep;
     208              :     } else {
     209              :         // set next step
     210            0 :         myLastTestStep->setNextStep(internalTestStep);
     211            0 :         myLastTestStep = internalTestStep;
     212              :     }
     213            0 : }
     214              : 
     215              : 
     216              : InternalTestStep*
     217            0 : InternalTest::getCurrentStep() const {
     218            0 :     return myCurrentTestStep;
     219              : }
     220              : 
     221              : 
     222              : InternalTestStep*
     223            0 : InternalTest::setNextStep() {
     224            0 :     const auto currentStep = myCurrentTestStep;
     225            0 :     myCurrentTestStep = myCurrentTestStep->getNextStep();
     226            0 :     return currentStep;
     227              : }
     228              : 
     229              : 
     230              : bool
     231            0 : InternalTest::isRunning() const {
     232            0 :     return myRunning;
     233              : }
     234              : 
     235              : 
     236              : void
     237            0 : InternalTest::stopTests() {
     238            0 :     myRunning = false;
     239            0 : }
     240              : 
     241              : 
     242              : FXint
     243            0 : InternalTest::getTime() const {
     244              :     return static_cast<FXuint>(
     245              :                std::chrono::duration_cast<std::chrono::milliseconds>(
     246            0 :                    std::chrono::steady_clock::now().time_since_epoch()
     247            0 :                ).count());
     248              : }
     249              : 
     250              : 
     251              : const std::map<std::string, int>&
     252            0 : InternalTest::getAttributesEnum() const {
     253            0 :     return myAttributesEnum;
     254              : }
     255              : 
     256              : 
     257              : const std::map<std::string, InternalTest::ContextualMenu>&
     258            0 : InternalTest::getContextualMenuOperations() const {
     259            0 :     return myContextualMenuOperations;
     260              : }
     261              : 
     262              : 
     263              : const std::map<std::string, InternalTest::ViewPosition>&
     264            0 : InternalTest::getViewPositions() const {
     265            0 :     return myViewPositions;
     266              : }
     267              : 
     268              : 
     269              : const std::map<std::string, InternalTest::Movement>&
     270            0 : InternalTest::getMovements() const {
     271            0 :     return myMovements;
     272              : }
     273              : 
     274              : 
     275              : const InternalTest::ViewPosition&
     276            0 : InternalTest::getLastMovedPosition() const {
     277            0 :     return myLastMovedPosition;
     278              : }
     279              : 
     280              : 
     281              : void
     282            0 : InternalTest::updateLastMovedPosition(const int x, const int y) {
     283            0 :     myLastMovedPosition = InternalTest::ViewPosition(x, y);
     284            0 : }
     285              : 
     286              : 
     287              : std::vector<InternalTest::ViewPosition>
     288            0 : InternalTest::interpolateViewPositions(const InternalTest::ViewPosition& viewStartPosition,
     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            0 :     trajectory.reserve(numPointsInterpolation);
     295              :     // calulate from using offsets
     296            0 :     const auto from = InternalTest::ViewPosition(viewStartPosition.getX() + offsetStartX, viewStartPosition.getY() + offsetStartY);
     297            0 :     const auto to = InternalTest::ViewPosition(viewEndPosition.getX() + offsetEndX, viewEndPosition.getY() + offsetEndY);
     298              :     // itearte over the number of points to interpolate
     299            0 :     for (int i = 0; i < numPointsInterpolation; i++) {
     300            0 :         const double t = static_cast<double>(i) / (numPointsInterpolation - 1); // t in [0, 1]
     301              :         // calculate interpolated position
     302            0 :         const int interpolatedX = int(from.getX() + t * (to.getX() - from.getX()));
     303            0 :         const int interpolatedY = int(from.getY() + t * (to.getY() - from.getY()));
     304              :         // add interpolated position
     305            0 :         trajectory.push_back(ViewPosition(interpolatedX, interpolatedY));
     306              :     }
     307            0 :     return trajectory;
     308            0 : }
     309              : 
     310              : 
     311              : std::map<std::string, int>
     312            0 : InternalTest::parseAttributesEnumFile(const std::string filePath) const {
     313              :     std::map<std::string, int> solution;
     314              :     // open file
     315            0 :     std::ifstream strm(filePath);
     316              :     // check if file can be opened
     317            0 :     if (!strm.good()) {
     318            0 :         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            0 :         while (std::getline(strm, line)) {
     323              :             // use stringstream for
     324            0 :             std::stringstream ss(line);
     325              :             // read key and value
     326              :             std::string key;
     327              :             std::string value;
     328            0 :             std::getline(ss, key, ' ');
     329            0 :             std::getline(ss, value, '\n');
     330              :             // check that int can be parsed
     331            0 :             if (!StringUtils::isInt(value)) {
     332            0 :                 WRITE_ERRORF(TL("In internal test file, value '%' cannot be parsed to int."), value);
     333              :             } else {
     334            0 :                 solution[key] = StringUtils::toInt(value);
     335              :             }
     336            0 :         }
     337              :     }
     338            0 :     return solution;
     339            0 : }
     340              : 
     341              : 
     342              : std::map<std::string, InternalTest::ContextualMenu>
     343            0 : InternalTest::parseContextualMenuOperationsFile(const std::string filePath) const {
     344              :     std::map<std::string, InternalTest::ContextualMenu> solution;
     345              :     // open file
     346            0 :     std::ifstream strm(filePath);
     347              :     // check if file can be opened
     348            0 :     if (!strm.good()) {
     349            0 :         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            0 :         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            0 :             std::stringstream mainMenuSS(line);
     363            0 :             std::getline(mainMenuSS, mainMenuKey, ' ');
     364            0 :             std::getline(mainMenuSS, mainMenuValue, '\n');
     365              :             // parse second line
     366            0 :             std::getline(strm, line);
     367            0 :             std::stringstream subMenuASS(line);
     368            0 :             std::getline(subMenuASS, subMenuAKey, ' ');
     369            0 :             std::getline(subMenuASS, subMenuAValue, '\n');
     370              :             // parse third line
     371            0 :             std::getline(strm, line);
     372            0 :             std::stringstream subMenuBSS(line);
     373            0 :             std::getline(subMenuBSS, subMenuBKey, ' ');
     374            0 :             std::getline(subMenuBSS, subMenuBValue, '\n');
     375              :             // check that int can be parsed
     376            0 :             if (!StringUtils::isInt(mainMenuValue)) {
     377            0 :                 WRITE_ERRORF(TL("In internal test file, mainMenu value '%' cannot be parsed to int."), mainMenuValue);
     378            0 :             } else if (!StringUtils::isInt(subMenuAValue)) {
     379            0 :                 WRITE_ERRORF(TL("In internal test file, subMenuA value '%' cannot be parsed to int."), subMenuAValue);
     380            0 :             } else if (!StringUtils::isInt(subMenuBValue)) {
     381            0 :                 WRITE_ERRORF(TL("In internal test file, subMenuB value '%' cannot be parsed to int."), subMenuBValue);
     382              :             } else {
     383              :                 // remove '.mainMenuPosition' from mainMenuKey
     384            0 :                 solution[mainMenuKey.erase(mainMenuKey.size() - 17)] = InternalTest::ContextualMenu(mainMenuValue, subMenuAValue, subMenuBValue);
     385              :             }
     386            0 :         }
     387              :     }
     388            0 :     return solution;
     389            0 : }
     390              : 
     391              : 
     392              : std::map<std::string, InternalTest::ViewPosition>
     393            0 : InternalTest::parseViewPositionsFile(const std::string filePath) const {
     394              :     std::map<std::string, InternalTest::ViewPosition> solution;
     395              :     // open file
     396            0 :     std::ifstream strm(filePath);
     397              :     // check if file can be opened
     398            0 :     if (!strm.good()) {
     399            0 :         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            0 :         while (std::getline(strm, line)) {
     404              :             // use stringstream for
     405            0 :             std::stringstream ss(line);
     406              :             // read key and value
     407              :             std::string key;
     408              :             std::string xValue;
     409              :             std::string yValue;
     410            0 :             std::getline(ss, key, ' ');
     411            0 :             std::getline(ss, xValue, ' ');
     412            0 :             std::getline(ss, yValue, '\n');
     413              :             // check that int can be parsed
     414            0 :             if (!StringUtils::isInt(xValue)) {
     415            0 :                 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), xValue);
     416            0 :             } else if (!StringUtils::isInt(yValue)) {
     417            0 :                 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), yValue);
     418              :             } else {
     419            0 :                 solution[key] = InternalTest::ViewPosition(xValue, yValue);
     420              :             }
     421            0 :         }
     422              :     }
     423            0 :     return solution;
     424            0 : }
     425              : 
     426              : 
     427              : std::map<std::string, InternalTest::Movement>
     428            0 : InternalTest::parseMovementsFile(const std::string filePath) const {
     429              :     std::map<std::string, InternalTest::Movement> solution;
     430              :     // open file
     431            0 :     std::ifstream strm(filePath);
     432              :     // check if file can be opened
     433            0 :     if (!strm.good()) {
     434            0 :         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            0 :         while (std::getline(strm, line)) {
     439              :             // use stringstream for
     440            0 :             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            0 :             std::getline(ss, key, ' ');
     448            0 :             std::getline(ss, upValue, ' ');
     449            0 :             std::getline(ss, downValue, ' ');
     450            0 :             std::getline(ss, leftValue, ' ');
     451            0 :             std::getline(ss, rightValue, '\n');
     452              :             // check that int can be parsed
     453            0 :             if (!StringUtils::isInt(upValue)) {
     454            0 :                 WRITE_ERRORF(TL("In internal test file, x value '%' cannot be parsed to int."), upValue);
     455            0 :             } else if (!StringUtils::isInt(downValue)) {
     456            0 :                 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), downValue);
     457            0 :             } else if (!StringUtils::isInt(leftValue)) {
     458            0 :                 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), leftValue);
     459            0 :             } else if (!StringUtils::isInt(rightValue)) {
     460            0 :                 WRITE_ERRORF(TL("In internal test file, y value '%' cannot be parsed to int."), rightValue);
     461              :             } else {
     462            0 :                 solution[key] = InternalTest::Movement(upValue, downValue, leftValue, rightValue);
     463              :             }
     464            0 :         }
     465              :     }
     466            0 :     return solution;
     467            0 : }
     468              : 
     469              : 
     470              : std::vector<std::string>
     471            0 : InternalTest::cleanLines(const std::vector<std::pair<bool, std::string> >& linesRaw) const {
     472              :     std::vector<std::string> results;
     473            0 :     for (const auto& lineRaw : linesRaw) {
     474            0 :         if (lineRaw.first) {
     475            0 :             results.push_back(lineRaw.second);
     476            0 :         } else if (results.size() > 0) {
     477              :             results.back().append(lineRaw.second);
     478              :         }
     479              :     }
     480            0 :     return results;
     481            0 : }
     482              : 
     483              : 
     484              : bool
     485            0 : InternalTest::startWith(const std::string& str, const std::string& prefix) const {
     486            0 :     if (prefix.size() > str.size()) {
     487              :         return false;
     488              :     } else {
     489            0 :         for (int i = 0; i < (int)prefix.size(); i++) {
     490            0 :             if (str[i] != prefix[i]) {
     491              :                 return false;
     492              :             }
     493              :         }
     494              :         return true;
     495              :     }
     496              : }
     497              : 
     498              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1