/* * Copyright 2014 Google Inc. All rights reserved. * * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF * ANY KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.google.maps; import com.google.maps.DirectionsApi.RouteRestriction; import com.google.maps.errors.NotFoundException; import com.google.maps.model.AddressType; import com.google.maps.model.DirectionsResult; import com.google.maps.model.GeocodedWaypointStatus; import com.google.maps.model.LatLng; import com.google.maps.model.TrafficModel; import com.google.maps.model.TransitMode; import com.google.maps.model.TransitRoutingPreference; import com.google.maps.model.TravelMode; import com.google.maps.model.Unit; import org.joda.time.DateTime; import org.joda.time.Duration; import org.joda.time.Instant; import org.junit.Test; import org.junit.experimental.categories.Category; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @Category(LargeTests.class) public class DirectionsApiTest extends AuthenticatedTest { private GeoApiContext context; public DirectionsApiTest(GeoApiContext context) { this.context = context .setQueryRateLimit(3) .setConnectTimeout(1, TimeUnit.SECONDS) .setReadTimeout(1, TimeUnit.SECONDS) .setWriteTimeout(1, TimeUnit.SECONDS); } @Test public void testGetDirections() throws Exception { DirectionsResult result = DirectionsApi.getDirections(context, "Sydney, AU", "Melbourne, AU").await(); assertNotNull(result.routes); assertNotNull(result.routes[0]); assertThat(result.routes[0].overviewPolyline.decodePath().size(), not(0)); assertTrue(result.routes[0].legs[0].startAddress.startsWith("Sydney NSW")); assertTrue(result.routes[0].legs[0].endAddress.startsWith("Melbourne VIC")); } @Test public void testBuilder() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .mode(TravelMode.BICYCLING) .avoid(RouteRestriction.HIGHWAYS, RouteRestriction.TOLLS, RouteRestriction.FERRIES) .units(Unit.METRIC) .region("au") .origin("Sydney") .destination("Melbourne").await(); assertNotNull(result.routes); assertNotNull(result.routes[0]); } @Test public void testTravelModeRoundTrip() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .mode(TravelMode.WALKING) .origin("483 George St, Sydney NSW 2000, Australia") .destination("182 Church St, Parramatta NSW 2150, Australia").await(); assertNotNull(result.routes); assertNotNull(result.routes[0]); assertEquals(TravelMode.WALKING, result.routes[0].legs[0].steps[0].travelMode); } @Test public void testResponseTimesArePopulatedCorrectly() throws Exception { DateTime now = new DateTime(); DirectionsResult result = DirectionsApi.newRequest(context) .mode(TravelMode.TRANSIT) .origin("483 George St, Sydney NSW 2000, Australia") .destination("182 Church St, Parramatta NSW 2150, Australia") .departureTime(now) .await(); assertNotNull(result.routes); assertNotNull(result.routes[0]); assertNotNull(result.routes[0].legs); assertNotNull(result.routes[0].legs[0]); assertNotNull(result.routes[0].legs[0].arrivalTime); assertNotNull(result.routes[0].legs[0].departureTime); } /** * A simple query from Toronto to Montreal. * * {@code http://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal} */ @Test public void testTorontoToMontreal() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Toronto") .destination("Montreal").await(); assertNotNull(result.routes); } /** * Going from Toronto to Montreal by bicycle, avoiding highways. * * {@code http://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&avoid=highways&mode=bicycling} */ @Test public void testTorontoToMontrealByBicycleAvoidingHighways() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Toronto") .destination("Montreal") .avoid(RouteRestriction.HIGHWAYS) .mode(TravelMode.BICYCLING) .await(); assertNotNull(result.routes); } /** * Brooklyn to Queens by public transport. * * {@code http://maps.googleapis.com/maps/api/directions/json?origin=Brooklyn&destination=Queens&departure_time=1343641500&mode=transit} */ @Test public void testBrooklynToQueensByTransit() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Brooklyn") .destination("Queens") .departureTime(new DateTime(1343641500)) .mode(TravelMode.TRANSIT) .await(); assertNotNull(result.routes); } /** * Boston to Concord, via Charlestown and Lexington. * * {@code http://maps.googleapis.com/maps/api/directions/json?origin=Boston,MA&destination=Concord,MA&waypoints=Charlestown,MA|Lexington,MA} */ @Test public void testBostonToConcordViaCharlestownAndLexignton() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Boston,MA") .destination("Concord,MA") .waypoints("Charlestown,MA", "Lexington,MA") .await(); assertNotNull(result.routes); } /** * Boston to Concord, via Charlestown and Lexington, but using exact latitude and longitude coordinates for the waypoints. * * {@code http://maps.googleapis.com/maps/api/directions/json?origin=Boston,MA&destination=Concord,MA&waypoints=42.379322,-71.063384|42.444303,-71.229087} */ @Test public void testBostonToConcordViaCharlestownAndLexigntonLatLng() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Boston,MA") .destination("Concord,MA") .waypoints(new LatLng(42.379322, -71.063384), new LatLng(42.444303, -71.229087)) .await(); assertNotNull(result.routes); } /** * Toledo to Madrid, in Spain. This showcases region biasing results. * * {@code http://maps.googleapis.com/maps/api/directions/json?origin=Toledo&destination=Madrid®ion=es} */ @Test public void testToledoToMadridInSpain() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Toledo") .destination("Madrid") .region("es") .await(); assertNotNull(result.routes); } /** * This is the same query above, without region biasing. It returns no routes. * * {@code http://maps.googleapis.com/maps/api/directions/json?origin=Toledo&destination=Madrid} */ @Test public void testToledoToMadridNotSpain() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Toledo") .destination("Madrid") .await(); assertNotNull(result.routes); assertEquals(0, result.routes.length); } /** * Test the language parameter. */ @Test public void testLanguageParameter() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Toledo") .destination("Madrid") .region("es") .language("es") .await(); assertNotNull(result.routes); } /** * Tests the {@code traffic_model} and {@code duration_in_traffic} parameters. */ @Test public void testTrafficModel() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("48 Pirrama Road, Pyrmont NSW 2009") .destination("182 Church St, Parramatta NSW 2150") .mode(TravelMode.DRIVING) .departureTime(new DateTime().plus(Duration.standardMinutes(2))) .trafficModel(TrafficModel.PESSIMISTIC) .await(); assertNotNull(result); assertTrue(result.routes.length > 0); assertTrue(result.routes[0].legs.length > 0); assertNotNull(result.routes[0].legs[0].durationInTraffic); } /** * Test transit without arrival or departure times specified. */ @Test public void testTransitWithoutSpecifyingTime() throws Exception { DirectionsApi.newRequest(context) .origin("Fisherman's Wharf, San Francisco") .destination("Union Square, San Francisco") .mode(TravelMode.TRANSIT) .await(); // Since this test may run at different times-of-day, it's entirely valid to return zero // routes, but the main thing to catch is that no exception is thrown. } /** * Test the extended transit parameters: mode and routing preference. */ @Test public void testTransitParams() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("Fisherman's Wharf, San Francisco") .destination("Union Square, San Francisco") .mode(TravelMode.TRANSIT) .transitMode(TransitMode.BUS, TransitMode.TRAM) .transitRoutingPreference(TransitRoutingPreference.LESS_WALKING) .await(); assertTrue(result.routes.length > 0); } @Test(expected = NotFoundException.class) public void testNotFound() throws Exception { DirectionsApi.getDirections(context, "fksjdhgf", "faldfdaf").await(); } /** * Test GeocodedWaypoints results. */ @Test public void testGeocodedWaypoints() throws Exception { DirectionsResult result = DirectionsApi.newRequest(context) .origin("48 Pirrama Rd, Pyrmont NSW") .destination("Airport Dr, Sydney NSW") .mode(TravelMode.DRIVING) .await(); assertNotNull(result.geocodedWaypoints); assertEquals(2, result.geocodedWaypoints.length); assertEquals(GeocodedWaypointStatus.OK, result.geocodedWaypoints[0].geocoderStatus); assertEquals(GeocodedWaypointStatus.OK, result.geocodedWaypoints[1].geocoderStatus); assertEquals(AddressType.ROUTE, result.geocodedWaypoints[1].types[0]); } /** * Tests that calling optimizeWaypoints before waypoints works and results in reordered waypoints. */ @Test public void testOptimizeWaypointsCallOrder1() { List<LatLng> waypoints = getOptimizationWaypoints(); DirectionsApiRequest request = DirectionsApi.newRequest(context) .origin(waypoints.get(0)) .destination(waypoints.get(1)) .departureTime(Instant.now()) .optimizeWaypoints(true) .waypoints(waypoints.subList(2, waypoints.size()).toArray(new LatLng[0])); DirectionsResult result = request.awaitIgnoreError(); assertWaypointsOptimized(result); } /** * Tests that calling optimizeWaypoints after waypoints works and results in reordered waypoints. */ @Test public void testOptimizeWaypointsCallOrder2() { List<LatLng> waypoints = getOptimizationWaypoints(); DirectionsApiRequest request = DirectionsApi.newRequest(context) .origin(waypoints.get(0)) .destination(waypoints.get(1)) .departureTime(Instant.now()) .waypoints(waypoints.subList(2, waypoints.size()).toArray(new LatLng[0])) .optimizeWaypoints(true); DirectionsResult result = request.awaitIgnoreError(); assertWaypointsOptimized(result); } private void assertWaypointsOptimized(DirectionsResult result) { int[] waypointOrder = result.routes[0].waypointOrder; assertNotNull(waypointOrder); assertTrue(waypointOrder.length > 0); for (int i = 0; i < waypointOrder.length; i++) { if (i != waypointOrder[i]) { return; } } fail("Waypoints do not appear to have been reordered."); } /** * Coordinates in Mexico City. Waypoints are out of order, so when optimized their order should change. */ private List<LatLng> getOptimizationWaypoints() { List<LatLng> waypoints = new ArrayList<LatLng>(); waypoints.add(new LatLng(19.431676,-99.133999)); waypoints.add(new LatLng(19.427915,-99.138939)); waypoints.add(new LatLng(19.435436,-99.139145)); waypoints.add(new LatLng(19.396436,-99.157176)); waypoints.add(new LatLng(19.427705,-99.198858)); waypoints.add(new LatLng(19.425869,-99.160716)); return waypoints; } }