@@ -10,14 +10,19 @@ import com.mapbox.geojson.Point
1010import com.mapbox.geojson.utils.PolylineUtils
1111import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
1212import com.mapbox.navigation.base.options.NavigationOptions
13+ import com.mapbox.navigation.base.route.NavigationRoute
14+ import com.mapbox.navigation.base.trip.model.RouteProgress
1315import com.mapbox.navigation.core.MapboxNavigation
1416import com.mapbox.navigation.core.directions.session.RoutesObserver
1517import com.mapbox.navigation.core.directions.session.RoutesUpdatedResult
1618import com.mapbox.navigation.core.replay.MapboxReplayer
1719import com.mapbox.navigation.core.replay.history.ReplayEventBase
1820import com.mapbox.navigation.core.replay.history.ReplayEventUpdateLocation
1921import com.mapbox.navigation.core.replay.history.ReplayEventsObserver
22+ import com.mapbox.navigation.core.trip.session.RouteProgressObserver
2023import com.mapbox.navigation.testing.LoggingFrontendTestRule
24+ import com.mapbox.turf.TurfConstants
25+ import com.mapbox.turf.TurfMeasurement
2126import io.mockk.every
2227import io.mockk.just
2328import io.mockk.mockk
@@ -47,9 +52,13 @@ class ReplayRouteSessionTest {
4752 private val options: NavigationOptions = mockk {
4853 every { applicationContext } returns context
4954 }
55+ private val routesObserver = slot<RoutesObserver >()
56+ private val routeProgressObserver = slot<RouteProgressObserver >()
5057 private val mapboxNavigation: MapboxNavigation = mockk(relaxed = true ) {
5158 every { mapboxReplayer } returns replayer
5259 every { navigationOptions } returns options
60+ every { registerRoutesObserver(capture(routesObserver)) } just runs
61+ every { registerRouteProgressObserver(capture(routeProgressObserver)) } just runs
5362 }
5463 private val bestLocationEngine: LocationEngine = mockk {
5564 every { getLastLocation(any()) } just runs
@@ -166,16 +175,14 @@ class ReplayRouteSessionTest {
166175
167176 @Test
168177 fun `onAttached - should push the initial batch of events` () {
169- val routesObserver = slot<RoutesObserver >()
170- every { mapboxNavigation.registerRoutesObserver(capture(routesObserver)) } just runs
171178 sut.setOptions(
172179 ReplayRouteSessionOptions .Builder ()
173180 .decodeMinDistance(1.0 )
174181 .build()
175182 )
176183
177184 sut.onAttached(mapboxNavigation)
178- routesObserver .captured.onRoutesChanged(mockActiveNavigationRoutes( ))
185+ routeProgressObserver .captured.onRouteProgressChanged(mockRouteProgress( 0.0 ))
179186
180187 val pushedEvents = slot<List <ReplayEventBase >>()
181188 verify { replayer.pushEvents(capture(pushedEvents)) }
@@ -193,24 +200,27 @@ class ReplayRouteSessionTest {
193200 replayEventsObserver.captured.replayEvents(firstArg())
194201 replayer
195202 }
196- val routesUpdatedResult = mockActiveNavigationRoutes( )
203+ val routeProgress = mockRouteProgress( 0.0 )
197204
198205 sut.setOptions(
199206 ReplayRouteSessionOptions .Builder ()
200207 .decodeMinDistance(0.001 )
201208 .build()
202209 )
203210 sut.onAttached(mapboxNavigation)
204- routesObserver .captured.onRoutesChanged(routesUpdatedResult )
211+ routeProgressObserver .captured.onRouteProgressChanged(routeProgress )
205212
206213 // Verify every point in the geometry was simulated
207214 val pushedPoints = pushedEvents.flatten().toList().map {
208215 val location = (it as ReplayEventUpdateLocation ).location
209216 Point .fromLngLat(location.lon, location.lat)
210217 }
211- val geometry = routesUpdatedResult.navigationRoutes.first() .directionsRoute.geometry()!!
218+ val geometry = routeProgress.navigationRoute .directionsRoute.geometry()!!
212219 val geometryPoints = PolylineUtils .decode(geometry, 6 )
213- assertTrue(pushedPoints.size > geometryPoints.size)
220+ assertTrue(
221+ " ${pushedPoints.size} > ${geometryPoints.size} " ,
222+ pushedPoints.size > geometryPoints.size
223+ )
214224 assertTrue(
215225 geometryPoints.all { lhs ->
216226 pushedPoints.firstOrNull { rhs -> lhs.equals(rhs) } != null
@@ -242,6 +252,9 @@ class ReplayRouteSessionTest {
242252
243253 sut.setOptions(ReplayRouteSessionOptions .Builder ().locationResetEnabled(true ).build())
244254 sut.onAttached(mapboxNavigation)
255+ routesObserver.captured.onRoutesChanged(
256+ mockk { every { navigationRoutes } returns emptyList() }
257+ )
245258 locationCallbackSlot.captured.onSuccess(
246259 mockk {
247260 every { lastLocation } returns mockk(relaxed = true ) {
@@ -263,21 +276,115 @@ class ReplayRouteSessionTest {
263276 assertEquals(- 2.0 , capturedLocation.location.lon, 0.0 )
264277 }
265278
266- private fun mockActiveNavigationRoutes (): RoutesUpdatedResult = mockk {
279+ @Test
280+ fun `onAttached registered listeners should be unregistered onDetached` () {
281+ val progressObserver = slot<RouteProgressObserver >()
282+ val routesObserver = slot<RoutesObserver >()
283+ val replayEventsObserver = slot<ReplayEventsObserver >()
284+ every { mapboxNavigation.registerRoutesObserver(capture(routesObserver)) } just runs
285+ every {
286+ mapboxNavigation.registerRouteProgressObserver(capture(progressObserver))
287+ } just runs
288+ every { replayer.registerObserver(capture(replayEventsObserver)) } just runs
289+
290+ sut.onAttached(mapboxNavigation)
291+ sut.onDetached(mapboxNavigation)
292+
293+ verifyOrder {
294+ mapboxNavigation.registerRouteProgressObserver(any())
295+ mapboxNavigation.registerRoutesObserver(any())
296+ replayer.registerObserver(any())
297+ mapboxNavigation.unregisterRoutesObserver(routesObserver.captured)
298+ mapboxNavigation.unregisterRouteProgressObserver(progressObserver.captured)
299+ replayer.unregisterObserver(replayEventsObserver.captured)
300+ }
301+ }
302+
303+ @Test
304+ fun `onAttached - should skip to the current routeProgress distanceTraveled` () {
305+ val progressObserver = slot<RouteProgressObserver >()
306+ val routesObserver = slot<RoutesObserver >()
307+ every {
308+ mapboxNavigation.registerRouteProgressObserver(capture(progressObserver))
309+ } just runs
310+ every { mapboxNavigation.registerRoutesObserver(capture(routesObserver)) } just runs
311+ val activeRoutes = mockActiveRoutesUpdatedResult()
312+ val primaryRoute = activeRoutes.navigationRoutes.first()
313+
314+ sut.onAttached(mapboxNavigation)
315+ progressObserver.captured.onRouteProgressChanged(
316+ mockk {
317+ every { navigationRoute } returns primaryRoute
318+ every { distanceTraveled } returns 100.0f
319+ }
320+ )
321+ routesObserver.captured.onRoutesChanged(activeRoutes)
322+
323+ val pushedEvents = slot<List <ReplayEventBase >>()
324+ verify { replayer.pushEvents(capture(pushedEvents)) }
325+ verifyDistanceTraveled(pushedEvents.captured, primaryRoute, 100.0 )
326+ }
327+
328+ @Test
329+ fun `onAttached - should skip to short routeProgress distanceTraveled` () {
330+ val progressObserver = slot<RouteProgressObserver >()
331+ val routesObserver = slot<RoutesObserver >()
332+ every {
333+ mapboxNavigation.registerRouteProgressObserver(capture(progressObserver))
334+ } just runs
335+ every { mapboxNavigation.registerRoutesObserver(capture(routesObserver)) } just runs
336+ val activeRoutes = mockActiveRoutesUpdatedResult()
337+ val primaryRoute = activeRoutes.navigationRoutes.first()
338+
339+ sut.onAttached(mapboxNavigation)
340+ progressObserver.captured.onRouteProgressChanged(
341+ mockk {
342+ every { navigationRoute } returns primaryRoute
343+ every { distanceTraveled } returns 40.0f
344+ }
345+ )
346+ routesObserver.captured.onRoutesChanged(activeRoutes)
347+
348+ val pushedEvents = slot<List <ReplayEventBase >>()
349+ verify { replayer.pushEvents(capture(pushedEvents)) }
350+ verifyDistanceTraveled(pushedEvents.captured, primaryRoute, 40.0 )
351+ }
352+
353+ private fun verifyDistanceTraveled (
354+ pushedEvents : List <ReplayEventBase >,
355+ primaryRoute : NavigationRoute ,
356+ distanceTraveled : Double
357+ ) {
358+ val geometry = primaryRoute.directionsRoute.geometry()!!
359+ val fullRoute = PolylineUtils .decode(geometry, 6 )
360+ val expected = TurfMeasurement .along(fullRoute, distanceTraveled, TurfConstants .UNIT_METERS )
361+ val firstReplayLocation = (pushedEvents.first() as ReplayEventUpdateLocation ).location
362+ val firstReplayPoint = Point .fromLngLat(firstReplayLocation.lon, firstReplayLocation.lat)
363+ val distanceToPoint = TurfMeasurement .distance(expected, firstReplayPoint)
364+
365+ assertTrue(" 1.0 > $distanceToPoint " , 1.0 > distanceToPoint)
366+ }
367+
368+ private fun mockActiveRoutesUpdatedResult (): RoutesUpdatedResult = mockk {
369+ every { navigationRoutes } returns listOf (mockNavigationRoute())
370+ }
371+
372+ private fun mockRouteProgress (traveled : Double ): RouteProgress = mockk {
373+ every { navigationRoute } returns mockNavigationRoute()
374+ every { distanceTraveled } returns traveled.toFloat()
375+ }
376+
377+ private fun mockNavigationRoute (): NavigationRoute = mockk {
267378 val geometry = " _kmbgAppafhFwXaOuC}ApAoEbNqe@jAaEhEcOtAwEdAoD`DaLnCiJ|M_e@`Je[rAyEnEgO" +
268379 " tGiUxByHlDjBp@^zKdG`Ah@`HtDx@d@rGlDl@\\ pAp@dAl@p@^nItEpQvJfAh@fDjB`D`Br@`@nKpFbDhB" +
269380 " ~KlGtDvBvAwE|EqPzFeSvHaXtA{ElAiE|@_D"
270- every { navigationRoutes } returns listOf (
271- mockk {
272- every { id } returns " test-navigation-route-id"
273- every { routeOptions }
274- every { directionsRoute } returns mockk {
275- every { routeOptions() } returns mockk {
276- every { geometries() } returns " polyline6"
277- every { geometry() } returns geometry
278- }
279- }
381+ every { id } returns " test-navigation-route-id"
382+ every { routeOptions }
383+ every { directionsRoute } returns mockk {
384+ every { routeOptions() } returns mockk {
385+ every { geometries() } returns " polyline6"
386+ every { geometry() } returns geometry
280387 }
281- )
388+ }
282389 }
283390}
0 commit comments