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

Generated by: LCOV version 2.0-1