From 09c98ddbab82d5b7e6dde4947a3660d2865b5efb Mon Sep 17 00:00:00 2001 From: Shan Ma <48976398+ShanMa1991@users.noreply.github.com> Date: Thu, 19 May 2022 14:43:15 -0700 Subject: [PATCH] Fix the crash of `routeRemainingDistancesIndex` after reroute. (#3896) --- CHANGELOG.md | 1 + ...NavigationMapView+VanishingRouteLine.swift | 4 +- .../VanishingRouteLineTests.swift | 53 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de37400fada..3ecafee7462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ * Fixed an issue where `UserPuckCourseView`’s color desaturated during turn-by-turn navigation even as the location was being updated. ([#3836](https://github.com/mapbox/mapbox-navigation-ios/pull/3836)) * Fixed an issue where the `PassiveLocationManager(directions:systemLocationManager:eventsManagerType:userInfo:datasetProfileIdentifier:)` initializer’s `datasetProfileIdentifier` argument was ignored. ([#3867](https://github.com/mapbox/mapbox-navigation-ios/pull/3867)) * Fixed an issue where the user location was sometimes snapped to a parallel street just before it merges with the actual street. ([#3862](https://github.com/mapbox/mapbox-navigation-ios/pull/3862)) +* Fix the possible crash after rerouting when `routeLineTracksTraversal` enabled. ([#3896](https://github.com/mapbox/mapbox-navigation-ios/pull/3896)) ### Routing diff --git a/Sources/MapboxNavigation/NavigationMapView+VanishingRouteLine.swift b/Sources/MapboxNavigation/NavigationMapView+VanishingRouteLine.swift index 2d07ee42931..a94521123ad 100644 --- a/Sources/MapboxNavigation/NavigationMapView+VanishingRouteLine.swift +++ b/Sources/MapboxNavigation/NavigationMapView+VanishingRouteLine.swift @@ -85,7 +85,7 @@ extension NavigationMapView { if currentStepProgress.distanceTraveled <= 0 { allRemainingPoints += currentLegSteps[currentLegProgress.stepIndex].dropLast().count } else if let startIndex = lineString.indexedCoordinateFromStart(distance: currentStepProgress.distanceTraveled)?.index, - startIndex < lineString.coordinates.endIndex - 1 { + lineString.coordinates.indices.contains(startIndex) { allRemainingPoints += lineString.coordinates.suffix(from: startIndex + 1).dropLast().count } @@ -154,7 +154,7 @@ extension NavigationMapView { func updateFractionTraveled(coordinate: CLLocationCoordinate2D) { guard let granularDistances = routeLineGranularDistances, let index = routeRemainingDistancesIndex, - index < granularDistances.distanceArray.endIndex else { return } + granularDistances.distanceArray.indices.contains(index) else { return } let traveledIndex = granularDistances.distanceArray[index] let upcomingPoint = traveledIndex.point diff --git a/Tests/MapboxNavigationTests/VanishingRouteLineTests.swift b/Tests/MapboxNavigationTests/VanishingRouteLineTests.swift index 7267ed0cf2d..736ff4bfa3c 100644 --- a/Tests/MapboxNavigationTests/VanishingRouteLineTests.swift +++ b/Tests/MapboxNavigationTests/VanishingRouteLineTests.swift @@ -64,6 +64,30 @@ class VanishingRouteLineTests: TestCase { return routeProgress } + func getEmptyRoute() -> Route { + let route = getRoute() + let routeLeg = route.legs.first! + let emptySteps = routeLeg.steps.map { (routeStep: RouteStep) -> RouteStep in + routeStep.shape?.coordinates = [] + return routeStep + } + let emptyLeg = RouteLeg(steps: emptySteps, + name: routeLeg.name, + distance: routeLeg.distance, + expectedTravelTime: routeLeg.expectedTravelTime, + profileIdentifier: routeLeg.profileIdentifier) + let emptyRoute = Route(legs: [emptyLeg], shape: route.shape, distance: route.distance, expectedTravelTime: route.expectedTravelTime) + return emptyRoute + } + + func getUnstartedRouteProgress(route: Route) -> RouteProgress { + let routeProgress = RouteProgress(route: route, options: routeOptions, legIndex: 0, spokenInstructionIndex: 0) + routeProgress.currentLegProgress = RouteLegProgress(leg: route.legs[0], stepIndex: 0, spokenInstructionIndex: 0) + routeProgress.currentLegProgress.currentStepProgress = RouteStepProgress(step: route.legs[0].steps[0], spokenInstructionIndex: 0) + routeProgress.currentLegProgress.currentStepProgress.distanceTraveled = 0.0 + return routeProgress + } + func lineGradientToString(lineGradient: Value?) -> String { guard let halfStringFromLineGradient = lineGradient.debugDescription.components(separatedBy: "(").last, let stringFromLineGradient = halfStringFromLineGradient.components(separatedBy: ")").first else { @@ -142,6 +166,35 @@ class VanishingRouteLineTests: TestCase { XCTAssertEqual(navigationMapView.fractionTraveled, expectedFractionTraveled, accuracy: 0.0000000001) } + func testEmptyRouteWithValidRouteProgress() { + let routeProgress = getRouteProgress() + let route = getEmptyRoute() + + let coordinate = CLLocationCoordinate2DMake(-122.5237429, 37.975393) + navigationMapView.routeLineTracksTraversal = true + navigationMapView.show([route]) + navigationMapView.updateUpcomingRoutePointIndex(routeProgress: routeProgress) + navigationMapView.updateFractionTraveled(coordinate: coordinate) + + // Route without coordinates inside its steps would lead to invalid routeRemainingDistancesIndex. + XCTAssertEqual(navigationMapView.routeRemainingDistancesIndex, -1) + XCTAssertEqual(navigationMapView.fractionTraveled, 0.0, accuracy: 0) + } + + func testUnstartedRouteProgressWithValidRoute() { + let route = getRoute() + let routeProgress = getUnstartedRouteProgress(route: route) + + let coordinate = CLLocationCoordinate2DMake(-122.5237429, 37.975393) + navigationMapView.routeLineTracksTraversal = true + navigationMapView.show([route]) + navigationMapView.updateUpcomingRoutePointIndex(routeProgress: routeProgress) + navigationMapView.updateFractionTraveled(coordinate: coordinate) + + XCTAssert(navigationMapView.routeRemainingDistancesIndex! >= 0, "Non-empty route should have valid routeRemainingDistancesIndex.") + XCTAssertEqual(navigationMapView.fractionTraveled, 0.0, accuracy: 0) + } + func disabled_UpdateRouteLineWithDifferentDistance() { let routeProgress = getRouteProgress() let route = routeProgress.route