forked from organicmaps/organicmaps-tmp
[routing] Bugfixing in infrastructure of routing session state tests adding a test on changing states.
This commit is contained in:
parent
0f8ab84b7f
commit
02250fd501
1 changed files with 230 additions and 64 deletions
|
@ -20,13 +20,23 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace routing
|
||||
namespace
|
||||
{
|
||||
using namespace routing;
|
||||
using namespace std;
|
||||
|
||||
using chrono::seconds;
|
||||
using chrono::steady_clock;
|
||||
|
||||
vector<m2::PointD> kTestRoute = {{0., 1.}, {0., 2.}, {0., 3.}, {0., 4.}};
|
||||
vector<Segment> const kTestSegments({{0, 0, 0, true}, {0, 0, 1, true}, {0, 0, 2, true}});
|
||||
Route::TTurns const kTestTurns = {turns::TurnItem(3, turns::CarDirection::ReachedYourDestination)};
|
||||
Route::TTimes const kTestTimes({Route::TTimeItem(1, 5), Route::TTimeItem(2, 10),
|
||||
Route::TTimeItem(3, 15)});
|
||||
auto const kRouteBuildingMaxDuration = seconds(30);
|
||||
|
||||
void FillSubroutesInfo(Route & route);
|
||||
|
||||
// Simple router. It returns route given to him on creation.
|
||||
class DummyRouter : public IRouter
|
||||
{
|
||||
|
@ -53,14 +63,34 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static vector<m2::PointD> kTestRoute = {{0., 1.}, {0., 2.}, {0., 3.}, {0., 4.}};
|
||||
static vector<Segment> const kTestSegments({{0, 0, 0, true}, {0, 0, 1, true}, {0, 0, 2, true}});
|
||||
static Route::TTurns const kTestTurns = {
|
||||
turns::TurnItem(3, turns::CarDirection::ReachedYourDestination)};
|
||||
static Route::TTimes const kTestTimes({Route::TTimeItem(1, 5), Route::TTimeItem(2, 10),
|
||||
Route::TTimeItem(3, 15)});
|
||||
// Router which every next call of CalculateRoute() method return different return codes.
|
||||
class ReturnCodesRouter : public IRouter
|
||||
{
|
||||
public:
|
||||
ReturnCodesRouter(initializer_list<RouterResultCode> const & returnCodes,
|
||||
vector<m2::PointD> const & route)
|
||||
: m_returnCodes(returnCodes), m_route(route)
|
||||
{
|
||||
}
|
||||
|
||||
static auto kRouteBuildingMaxDuration = seconds(30);
|
||||
// IRouter overrides:
|
||||
string GetName() const override { return "return codes router"; }
|
||||
void ClearState() override {}
|
||||
RouterResultCode CalculateRoute(Checkpoints const & /* checkpoints */,
|
||||
m2::PointD const & /* startDirection */, bool /* adjust */,
|
||||
RouterDelegate const & /* delegate */, Route & route) override
|
||||
{
|
||||
TEST_LESS(m_returnCodesIdx, m_returnCodes.size(), ());
|
||||
route = Route(GetName(), m_route.begin(), m_route.end(), 0 /* route id */);
|
||||
FillSubroutesInfo(route);
|
||||
return m_returnCodes[m_returnCodesIdx++];
|
||||
}
|
||||
|
||||
private:
|
||||
vector<RouterResultCode> m_returnCodes;
|
||||
vector<m2::PointD> m_route;
|
||||
size_t m_returnCodesIdx = 0;
|
||||
};
|
||||
|
||||
class TimedSignal
|
||||
{
|
||||
|
@ -97,12 +127,34 @@ public:
|
|||
SessionStateTest(initializer_list<SessionState> expectedStates, RoutingSession & routingSession)
|
||||
: m_expectedStates(expectedStates), m_session(routingSession)
|
||||
{
|
||||
m_session.SetChangeSessionStateCallback([this](SessionState previous, SessionState current) {
|
||||
TestChangeSessionStateCallbackCall(previous, current);
|
||||
for (size_t i = 1; i < expectedStates.size(); ++i)
|
||||
{
|
||||
// Note. Change session state callback is called only if the state is change.
|
||||
if (m_expectedStates[i - 1] != m_expectedStates[i])
|
||||
++m_expectedNumberOfStateChanging;
|
||||
}
|
||||
|
||||
TimedSignal timedSignal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [this, &timedSignal]() {
|
||||
m_session.SetChangeSessionStateCallback([this](SessionState previous, SessionState current) {
|
||||
TestChangeSessionStateCallbackCall(previous, current);
|
||||
});
|
||||
timedSignal.Signal();
|
||||
});
|
||||
TEST(timedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Callback is not set."));
|
||||
}
|
||||
|
||||
~SessionStateTest() { m_session.SetChangeSessionStateCallback(nullptr); }
|
||||
~SessionStateTest()
|
||||
{
|
||||
TEST_EQUAL(m_numberOfTestCalls, m_expectedNumberOfStateChanging,
|
||||
("Wrong number of calls of SetState() callback.", m_expectedStates));
|
||||
TimedSignal timedSignal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [this, &timedSignal]() {
|
||||
m_session.SetChangeSessionStateCallback(nullptr);
|
||||
timedSignal.Signal();
|
||||
});
|
||||
TEST(timedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Callback is not set."));
|
||||
}
|
||||
|
||||
private:
|
||||
void TestChangeSessionStateCallbackCall(SessionState previous, SessionState current)
|
||||
|
@ -117,6 +169,7 @@ private:
|
|||
|
||||
size_t m_numberOfTestCalls = 0;
|
||||
vector<SessionState> const m_expectedStates;
|
||||
size_t m_expectedNumberOfStateChanging = 0;
|
||||
RoutingSession & m_session;
|
||||
};
|
||||
|
||||
|
@ -134,6 +187,36 @@ void FillSubroutesInfo(Route & route)
|
|||
{Route::SubrouteAttrs(junctions.front(), junctions.back(), 0, kTestSegments.size())}));
|
||||
}
|
||||
|
||||
void TestMovingByUpdatingLat(SessionStateTest const & sessionState, vector<double> const & lats,
|
||||
location::GpsInfo const & info, RoutingSession & session)
|
||||
{
|
||||
location::GpsInfo uptInfo(info);
|
||||
TimedSignal signal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [&session, &signal, &lats, &uptInfo]() {
|
||||
for (auto const lat : lats)
|
||||
{
|
||||
uptInfo.m_latitude = lat;
|
||||
session.OnLocationPositionChanged(uptInfo);
|
||||
}
|
||||
|
||||
signal.Signal();
|
||||
});
|
||||
TEST(signal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration),
|
||||
("Along route moving timeout."));
|
||||
}
|
||||
|
||||
void TestLeavingRoute(RoutingSession & session, location::GpsInfo const & info)
|
||||
{
|
||||
vector<double> const latitudes = {0.0, -0.001, -0.002, -0.003, -0.004, -0.005,
|
||||
-0.006, -0.007, -0.008, -0.009, -0.01, -0.011};
|
||||
SessionStateTest sessionStateTest({SessionState::OnRoute, SessionState::RouteNeedRebuild},
|
||||
session);
|
||||
TestMovingByUpdatingLat(sessionStateTest, latitudes, info, session);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace routing
|
||||
{
|
||||
UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteBuilding)
|
||||
{
|
||||
// Multithreading synchronization note. |counter| and |session| are constructed on the main thread,
|
||||
|
@ -170,7 +253,6 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteBuilding)
|
|||
UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingAway)
|
||||
{
|
||||
location::GpsInfo info;
|
||||
FrozenDataSource dataSource;
|
||||
size_t counter = 0;
|
||||
|
||||
TimedSignal alongTimedSignal;
|
||||
|
@ -194,40 +276,40 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingA
|
|||
TEST(alongTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built."));
|
||||
TEST_EQUAL(counter, 1, ());
|
||||
|
||||
TimedSignal oppositeTimedSignal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [&oppositeTimedSignal, &info, this]() {
|
||||
info.m_horizontalAccuracy = 0.01;
|
||||
info.m_verticalAccuracy = 0.01;
|
||||
info.m_longitude = 0.;
|
||||
info.m_latitude = 1.;
|
||||
SessionState code = SessionState::NoValidRoute;
|
||||
{
|
||||
SessionStateTest sessionStateTest(
|
||||
{SessionState::RouteNotStarted, SessionState::OnRoute, SessionState::RouteBuilding,
|
||||
SessionState::RouteNotStarted},
|
||||
*m_session);
|
||||
TimedSignal oppositeTimedSignal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [&oppositeTimedSignal, &info, this]() {
|
||||
info.m_horizontalAccuracy = 0.01;
|
||||
info.m_verticalAccuracy = 0.01;
|
||||
info.m_longitude = 0.;
|
||||
info.m_latitude = 1.;
|
||||
SessionState code = SessionState::NoValidRoute;
|
||||
|
||||
{
|
||||
SessionStateTest sessionStateTest({SessionState::RouteNotStarted, SessionState::OnRoute},
|
||||
*m_session);
|
||||
while (info.m_latitude < kTestRoute.back().y)
|
||||
{
|
||||
code = m_session->OnLocationPositionChanged(info);
|
||||
TEST_EQUAL(code, SessionState::OnRoute, ());
|
||||
info.m_latitude += 0.01;
|
||||
while (info.m_latitude < kTestRoute.back().y)
|
||||
{
|
||||
code = m_session->OnLocationPositionChanged(info);
|
||||
TEST_EQUAL(code, SessionState::OnRoute, ());
|
||||
info.m_latitude += 0.01;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild route and go in opposite direction. So initiate a route rebuilding flag.
|
||||
m_session->SetRoutingCallbacks(
|
||||
[&oppositeTimedSignal](Route const &, RouterResultCode) { oppositeTimedSignal.Signal(); },
|
||||
nullptr /* rebuildReadyCallback */, nullptr /* needMoreMapsCallback */,
|
||||
nullptr /* removeRouteCallback */);
|
||||
{
|
||||
SessionStateTest sessionStateTest(
|
||||
{SessionState::OnRoute, SessionState::RouteBuilding},
|
||||
*m_session);
|
||||
|
||||
m_session->BuildRoute(Checkpoints(kTestRoute.front(), kTestRoute.back()),
|
||||
RouterDelegate::kNoTimeout);
|
||||
}
|
||||
});
|
||||
TEST(oppositeTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built."));
|
||||
// Rebuild route and go in opposite direction. So initiate a route rebuilding flag.
|
||||
m_session->SetRoutingCallbacks(
|
||||
[&oppositeTimedSignal](Route const &, RouterResultCode) { oppositeTimedSignal.Signal(); },
|
||||
nullptr /* rebuildReadyCallback */, nullptr /* needMoreMapsCallback */,
|
||||
nullptr /* removeRouteCallback */);
|
||||
{
|
||||
m_session->BuildRoute(Checkpoints(kTestRoute.front(), kTestRoute.back()),
|
||||
RouterDelegate::kNoTimeout);
|
||||
}
|
||||
});
|
||||
TEST(oppositeTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built."));
|
||||
}
|
||||
|
||||
// Going away from route to set rebuilding flag.
|
||||
TimedSignal checkTimedSignal;
|
||||
|
@ -253,7 +335,6 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingA
|
|||
UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingToRoute)
|
||||
{
|
||||
location::GpsInfo info;
|
||||
FrozenDataSource dataSource;
|
||||
size_t counter = 0;
|
||||
|
||||
TimedSignal alongTimedSignal;
|
||||
|
@ -277,33 +358,34 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingT
|
|||
TEST_EQUAL(counter, 1, ());
|
||||
|
||||
// Going starting far from the route and moving to the route but rebuild flag still is set.
|
||||
TimedSignal checkTimedSignalAway;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [&checkTimedSignalAway, &info, this]() {
|
||||
info.m_longitude = 0.0;
|
||||
info.m_latitude = 0.0;
|
||||
info.m_speedMpS = routing::KMPH2MPS(60);
|
||||
SessionState code = SessionState::NoValidRoute;
|
||||
{
|
||||
SessionStateTest sessionStateTest(
|
||||
{SessionState::RouteNotStarted, SessionState::RouteNeedRebuild},
|
||||
*m_session);
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
SessionStateTest sessionStateTest(
|
||||
{SessionState::RouteNotStarted, SessionState::RouteNeedRebuild},
|
||||
*m_session);
|
||||
TimedSignal checkTimedSignalAway;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [&checkTimedSignalAway, &info, this]() {
|
||||
info.m_longitude = 0.0;
|
||||
info.m_latitude = 0.0;
|
||||
info.m_speedMpS = routing::KMPH2MPS(60);
|
||||
SessionState code = SessionState::NoValidRoute;
|
||||
{
|
||||
code = m_session->OnLocationPositionChanged(info);
|
||||
info.m_latitude += 0.1;
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
code = m_session->OnLocationPositionChanged(info);
|
||||
info.m_latitude += 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_EQUAL(code, SessionState::RouteNeedRebuild, ());
|
||||
checkTimedSignalAway.Signal();
|
||||
});
|
||||
TEST(checkTimedSignalAway.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration),
|
||||
("Route was not rebuilt."));
|
||||
TEST_EQUAL(code, SessionState::RouteNeedRebuild, ());
|
||||
checkTimedSignalAway.Signal();
|
||||
});
|
||||
TEST(checkTimedSignalAway.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration),
|
||||
("Route was not rebuilt."));
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRouteFlagPersistence)
|
||||
{
|
||||
location::GpsInfo info;
|
||||
FrozenDataSource dataSource;
|
||||
size_t counter = 0;
|
||||
|
||||
TimedSignal alongTimedSignal;
|
||||
|
@ -390,7 +472,6 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRouteFlagPersist
|
|||
|
||||
UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRoutePercentTest)
|
||||
{
|
||||
FrozenDataSource dataSource;
|
||||
TimedSignal alongTimedSignal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [&alongTimedSignal, this]() {
|
||||
InitRoutingSession();
|
||||
|
@ -452,4 +533,89 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRoutePercentTest
|
|||
TEST(checkTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration),
|
||||
("Route checking timeout."));
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingError)
|
||||
{
|
||||
vector<m2::PointD> const kRoute = {{0.0, 0.001}, {0.0, 0.002}, {0.0, 0.003}, {0.0, 0.004}};
|
||||
// Creation RoutingSession.
|
||||
TimedSignal createTimedSignal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [this, &kRoute, &createTimedSignal]() {
|
||||
InitRoutingSession();
|
||||
unique_ptr<ReturnCodesRouter> router = make_unique<ReturnCodesRouter>(initializer_list<
|
||||
RouterResultCode>{RouterResultCode::NoError, RouterResultCode::InternalError}, kRoute);
|
||||
m_session->SetRouter(move(router), nullptr);
|
||||
createTimedSignal.Signal();
|
||||
});
|
||||
TEST(createTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration),
|
||||
("RouteSession was not created."));
|
||||
|
||||
// Building a route.
|
||||
{
|
||||
SessionStateTest sessionStateTest(
|
||||
{SessionState::NoValidRoute, SessionState::RouteBuilding, SessionState::RouteNotStarted},
|
||||
*m_session);
|
||||
TimedSignal buildTimedSignal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [this, &kRoute, &buildTimedSignal]() {
|
||||
m_session->SetRoutingCallbacks(
|
||||
[&buildTimedSignal](Route const &, RouterResultCode) { buildTimedSignal.Signal(); },
|
||||
nullptr /* rebuildReadyCallback */, nullptr /* needMoreMapsCallback */,
|
||||
nullptr /* removeRouteCallback */);
|
||||
|
||||
m_session->BuildRoute(Checkpoints(kRoute.front(), kRoute.back()),
|
||||
RouterDelegate::kNoTimeout);
|
||||
});
|
||||
TEST(buildTimedSignal
|
||||
.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built."));
|
||||
}
|
||||
|
||||
location::GpsInfo info;
|
||||
info.m_horizontalAccuracy = 5.0; // meters
|
||||
info.m_verticalAccuracy = 5.0; // meters
|
||||
info.m_longitude = 0.0;
|
||||
|
||||
// Moving along route.
|
||||
{
|
||||
SessionStateTest sessionStateTest({SessionState::RouteNotStarted, SessionState::OnRoute},
|
||||
*m_session);
|
||||
vector<double> const latitudes = {0.001, 0.0015, 0.002};
|
||||
TestMovingByUpdatingLat(sessionStateTest, latitudes, info, *m_session);
|
||||
}
|
||||
|
||||
// Leaving the route until switching to |SessionState::RouteNeedRebuild| state.
|
||||
TestLeavingRoute(*m_session, info);
|
||||
|
||||
// Continue moving along the route.
|
||||
{
|
||||
SessionStateTest sessionStateTest({SessionState::RouteNeedRebuild, SessionState::OnRoute},
|
||||
*m_session);
|
||||
vector<double> const latitudes = {0.002, 0.0025, 0.003};
|
||||
TestMovingByUpdatingLat(sessionStateTest, latitudes, info, *m_session);
|
||||
}
|
||||
|
||||
// Leaving the route until switching to |SessionState::RouteRebuilding| state.
|
||||
TestLeavingRoute(*m_session, info);
|
||||
{
|
||||
SessionStateTest sessionStateTest(
|
||||
{SessionState::RouteNeedRebuild, SessionState::RouteRebuilding,
|
||||
SessionState::RouteNotStarted
|
||||
},
|
||||
*m_session);
|
||||
TimedSignal signal;
|
||||
GetPlatform().RunTask(Platform::Thread::Gui, [this, &signal]() {
|
||||
m_session->SetState(SessionState::RouteRebuilding);
|
||||
m_session->SetState(SessionState::RouteNotStarted);
|
||||
signal.Signal();
|
||||
});
|
||||
TEST(signal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration),
|
||||
("State was not set."));
|
||||
}
|
||||
|
||||
// Continue moving along the route again.
|
||||
{
|
||||
SessionStateTest sessionStateTest({SessionState::RouteNotStarted, SessionState::OnRoute},
|
||||
*m_session);
|
||||
vector<double> const latitudes = {0.003, 0.0035, 0.004};
|
||||
TestMovingByUpdatingLat(sessionStateTest, latitudes, info, *m_session);
|
||||
}
|
||||
}
|
||||
} // namespace routing
|
||||
|
|
Loading…
Add table
Reference in a new issue