#pragma once #include "routing/index_router.hpp" #include "routing/routing_callbacks.hpp" #include "storage/country_info_getter.hpp" #include "map/feature_vec_model.hpp" #include "platform/local_country_file.hpp" #include "std/set.hpp" #include "std/shared_ptr.hpp" #include "std/string.hpp" #include "std/unique_ptr.hpp" #include "std/utility.hpp" #include "std/vector.hpp" /* * These tests are developed to simplify routing integration tests writing. * You can use the interface bellow however you want but there are some hints. * 1. Most likely you want to use GetCarComponents() or GetPedestrianComponents() without parameter * to get a reference to IRouterComponents. * It loads all the maps from directories Platform::WritableDir() * and Platform::ResourcesDir() only once and then reuse it. * Use GetCarComponents() or GetPedestrianComponents() with vector of maps parameter * only if you want to test something on a special map set. * 2. Loading maps and calculating routes is a time consumption process. * Do this only if you really need it. * 3. If you want to check that a turn is absent - use TestTurnCount. * 4. The easiest way to gather all the information for writing an integration test is * - to put a break point in CalculateRoute() method; * - to make a route with MapWithMe desktop application; * - to get all necessary parameters and result of the route calculation; * - to place them into the test you're writing. * 5. The recommended way for naming tests for a route from one place to another one is * * 6. It's a good idea to use short routes for testing turns. The thing is geometry of long routes * could be changed from one dataset to another. The shorter the route the less is the chance it's changed. */ using namespace routing; using namespace turns; using platform::LocalCountryFile; typedef pair, RouterResultCode> TRouteResult; namespace integration { shared_ptr CreateFeaturesFetcher(vector const & localFiles); unique_ptr CreateCountryInfoGetter(); unique_ptr CreateVehicleRouter(DataSourceBase & dataSource, storage::CountryInfoGetter const & infoGetter, traffic::TrafficCache const & trafficCache, vector const & localFiles, VehicleType vehicleType); class IRouterComponents { public: IRouterComponents(vector const & localFiles) : m_featuresFetcher(CreateFeaturesFetcher(localFiles)), m_infoGetter(CreateCountryInfoGetter()) { } virtual ~IRouterComponents() = default; virtual IRouter & GetRouter() const = 0; storage::CountryInfoGetter const & GetCountryInfoGetter() const noexcept { return *m_infoGetter; } protected: shared_ptr m_featuresFetcher; unique_ptr m_infoGetter; }; class VehicleRouterComponents : public IRouterComponents { public: VehicleRouterComponents(vector const & localFiles, VehicleType vehicleType) : IRouterComponents(localFiles) , m_indexRouter(CreateVehicleRouter(m_featuresFetcher->GetDataSource(), *m_infoGetter, m_trafficCache, localFiles, vehicleType)) { } IRouter & GetRouter() const override { return *m_indexRouter; } private: traffic::TrafficCache m_trafficCache; unique_ptr m_indexRouter; }; void GetAllLocalFiles(vector & localFiles); void TestOnlineCrosses(ms::LatLon const & startPoint, ms::LatLon const & finalPoint, vector const & expected, IRouterComponents & routerComponents); void TestOnlineFetcher(ms::LatLon const & startPoint, ms::LatLon const & finalPoint, vector const & expected, IRouterComponents & routerComponents); shared_ptr CreateAllMapsComponents(VehicleType vehicleType); template IRouterComponents & GetVehicleComponents() { static auto const instance = CreateAllMapsComponents(type); ASSERT(instance, ()); return *instance; } TRouteResult CalculateRoute(IRouterComponents const & routerComponents, m2::PointD const & startPoint, m2::PointD const & startDirection, m2::PointD const & finalPoint); void TestTurnCount(Route const & route, uint32_t expectedTurnCount); /// Testing route length. /// It is used for checking if routes have expected(sample) length. /// A created route will pass the test iff /// expectedRouteMeters - expectedRouteMeters * relativeError <= route->GetDistance() /// && expectedRouteMeters + expectedRouteMeters * relativeError >= route->GetDistance() void TestRouteLength(Route const & route, double expectedRouteMeters, double relativeError = 0.01); void TestRouteTime(Route const & route, double expectedRouteSeconds, double relativeError = 0.01); void TestRoutePointsNumber(Route const & route, size_t expectedPointsNumber, double relativeError = 0.1); void CalculateRouteAndTestRouteLength(IRouterComponents const & routerComponents, m2::PointD const & startPoint, m2::PointD const & startDirection, m2::PointD const & finalPoint, double expectedRouteMeters, double relativeError = 0.07); class TestTurn { friend TestTurn GetNthTurn(Route const & route, uint32_t turnNumber); m2::PointD const m_point; CarDirection const m_direction; uint32_t const m_roundAboutExitNum; bool const m_isValid; TestTurn() : m_point({0.0, 0.0}) , m_direction(CarDirection::None) , m_roundAboutExitNum(0) , m_isValid(false) { } TestTurn(m2::PointD const & pnt, CarDirection direction, uint32_t roundAboutExitNum) : m_point(pnt), m_direction(direction), m_roundAboutExitNum(roundAboutExitNum), m_isValid(true) { } public: const TestTurn & TestValid() const; const TestTurn & TestNotValid() const; const TestTurn & TestPoint(m2::PointD const & expectedPoint, double inaccuracyMeters = 3.) const; const TestTurn & TestDirection(CarDirection expectedDirection) const; const TestTurn & TestOneOfDirections(set const & expectedDirections) const; const TestTurn & TestRoundAboutExitNum(uint32_t expectedRoundAboutExitNum) const; }; /// Extracting appropriate TestTurn if any. If not TestTurn::isValid() returns false. /// inaccuracy is set in meters. TestTurn GetNthTurn(Route const & route, uint32_t turnNumber); void TestCurrentStreetName(routing::Route const & route, string const & expectedStreetName); void TestNextStreetName(routing::Route const & route, string const & expectedStreetName); } // namespace integration