// // MKStepsTests.swift // FSRoutingLibIOsTests // // Created by David Meignan on 14.10.21. // Copyright © 2021 feelSpace GmbH. All rights reserved. // import XCTest import MapKit class MKStepsTests: XCTestCase { override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. } override func tearDownWithError() throws { // Put teardown code here. This method is called after the invocation of each test method in the class. } func testRouteSteps() throws { let originLocation = CLLocation( latitude: 37.338879, longitude: -122.012442) let destinationLocation = CLLocation( latitude: 37.339662, longitude: -122.010642) // X Destination (Kintyre Way) // | | // | | // o---o--------o (Leighton Way) // | // | // X Origin (Nightingale Ave) let routeRequestExpectation = XCTestExpectation() var directionsResponse: MKDirections.Response? = nil // Create route request let requestParameters = MKDirections.Request() requestParameters.source = MKMapItem( placemark: MKPlacemark(coordinate: originLocation.coordinate)) requestParameters.destination = MKMapItem( placemark: MKPlacemark(coordinate: destinationLocation.coordinate)) requestParameters.transportType = .walking requestParameters.requestsAlternateRoutes = false let routeRequest = MKDirections(request: requestParameters) // Send request routeRequest.calculate( completionHandler: {(response, error) -> Void in XCTAssertNil(error, "Route request failed.") directionsResponse = response routeRequestExpectation.fulfill() }) // Wait request completion wait(for: [routeRequestExpectation], timeout: 5) XCTAssertNotNil(directionsResponse, "No directions.") // Check specifically for MapKit-iOS15 bug // The geometry of the second step should not be the same single point than the first step let directionsSteps = directionsResponse!.routes[0].steps if (directionsSteps.count >= 2) { let firstStep = directionsSteps[0] let secondStep = directionsSteps[1] if firstStep.polyline.pointCount == 1 && secondStep.polyline.pointCount == 1 { // Test that coordinates are different let firstStepCoordinate = firstStep.polyline.points()[0].coordinate let secondStepCoordinate = firstStep.polyline.points()[0].coordinate XCTAssertTrue( firstStepCoordinate.latitude != secondStepCoordinate.latitude || firstStepCoordinate.longitude != secondStepCoordinate.longitude) } } // We should have exactly one route (no alternative route) XCTAssertTrue(directionsResponse!.routes.count == 1) // Ideally the end point of a step should be the start point of the next step for (stepIndex, step) in directionsSteps.enumerated().dropLast(1) { let nextStep = directionsSteps[stepIndex+1] let lastPoint = step.polyline.points()[step.polyline.pointCount-1].coordinate let firstPointNextStep = nextStep.polyline.points()[0].coordinate XCTAssertTrue( lastPoint.latitude == firstPointNextStep.latitude || lastPoint.longitude == firstPointNextStep.longitude) } // MARK: Tests that are specific to the origin/destination points // Print route geometry let routePolyline = directionsResponse?.routes[0].polyline print("Route geometry:") for routePointIndex in 0..<routePolyline!.pointCount { let point = routePolyline!.points()[routePointIndex] let previousPoint = routePointIndex>0 ? routePolyline?.points()[routePointIndex-1] : nil let distancePrevious = previousPoint?.distance(to: point) print("\(point.coordinate.latitude), \(point.coordinate.longitude) (distance form previous point: \(distancePrevious?.rounded() ?? 0) m)") } // Print details of the geometry of each step for (stepIndex, step) in directionsSteps.enumerated() { print("Step \(stepIndex)") print(" - Step geometry with \(step.polyline.pointCount) point(s)") // Search the start and end points on the route let stepStartPoint = step.polyline.points()[0] let stepEndPoint = step.polyline.points()[step.polyline.pointCount-1] var routeStepStartIndex = -1 var routeStepEndIndex = -1 for routePointIndex in 0..<routePolyline!.pointCount { let routePoint = routePolyline!.points()[routePointIndex] if stepStartPoint.distance(to: routePoint) < 1.0 { routeStepStartIndex = routePointIndex } if stepEndPoint.distance(to: routePoint) < 1.0 { routeStepEndIndex = routePointIndex } } if step.polyline.pointCount == 1 { print(" - Located on route point \(routeStepStartIndex)") } else { print(" - Start on route point \(routeStepStartIndex)") print(" - End on route point \(routeStepEndIndex)") } } // The polyline should have at least 4 points (actually 5) XCTAssertTrue(routePolyline!.pointCount >= 4) // We should have 4 steps and at least two maneuvers // 1. Start on Nightingale Ave (added since iOS 15 release) // 2. Take a right onto Leighton Way // 3. Take a left onto Kintyre Way // 4. Arrive at the destination XCTAssertTrue(directionsSteps.count >= 4) } }