diff --git a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ArrivalInfoRequestTest.java b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ArrivalInfoRequestTest.java index b0aa4bde3d..4d274bbb0e 100644 --- a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ArrivalInfoRequestTest.java +++ b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ArrivalInfoRequestTest.java @@ -710,4 +710,70 @@ public void testScheduledArrival() { assertTrue(arrivals[1].getPredicted()); assertFalse(arrivals[2].getPredicted()); } + + @Test + public void testFrequencyBasedTrips() { + // Test frequency-based trips using USF Bull Runner data (see issue #430). + // ObaTestCase.before() already sets the Puget Sound API URL, and the URI map + // resolves the USF request by path, so no setCustomApiUrl override is needed. + ObaArrivalInfoResponse response = + new ObaArrivalInfoRequest.Builder(getTargetContext(), + "USF Bull Runner_203").build().call(); + assertOK(response); + + ObaStop stop = response.getStop(); + assertNotNull(stop); + assertEquals("USF Bull Runner_203", stop.getId()); + assertEquals("Center for Transportation Research", stop.getName()); + + final List routes = response.getRoutes(stop.getRouteIds()); + assertEquals(2, routes.size()); + + final ObaArrivalInfo[] arrivals = response.getArrivalInfo(); + assertNotNull(arrivals); + assertEquals(2, arrivals.length); + + // First arrival - Route E (Gold Campus Loop) - frequency-based + ObaArrivalInfo arrival0 = arrivals[0]; + assertEquals("USF Bull Runner_E", arrival0.getRouteId()); + assertEquals("E", arrival0.getShortName()); + assertEquals("Gold Campus Loop", arrival0.getHeadsign()); + assertNotNull(arrival0.getFrequency()); + assertEquals(600, arrival0.getFrequency().getHeadway()); + assertEquals(1456747200000L, arrival0.getFrequency().getStartTime()); + assertEquals(1456808400000L, arrival0.getFrequency().getEndTime()); + assertFalse(arrival0.getPredicted()); + + // Second arrival - Route D (Red Off-Campus West) - frequency-based + ObaArrivalInfo arrival1 = arrivals[1]; + assertEquals("USF Bull Runner_D", arrival1.getRouteId()); + assertEquals("D", arrival1.getShortName()); + assertEquals("Red Off-Campus West", arrival1.getHeadsign()); + assertNotNull(arrival1.getFrequency()); + assertEquals(600, arrival1.getFrequency().getHeadway()); + assertEquals(1456747200000L, arrival1.getFrequency().getStartTime()); + assertEquals(1456808400000L, arrival1.getFrequency().getEndTime()); + assertFalse(arrival1.getPredicted()); + + // Verify nearby stops - the USF fixture contains exactly one nearby stop + final List nearbyStops = response.getNearbyStops(); + assertEquals(1, nearbyStops.size()); + assertEquals("USF Bull Runner_204", nearbyStops.get(0).getId()); + } + + @Test + public void testScheduleBasedTripHasNullFrequency() { + // Verify that a schedule-based trip (HART) has a null frequency + Application.get().setCustomApiUrl("api.tampa.onebusaway.org/api"); + + ObaArrivalInfoResponse response = + new ObaArrivalInfoRequest.Builder(getTargetContext(), + "Hillsborough Area Regional Transit_3105").build().call(); + assertOK(response); + + final ObaArrivalInfo[] arrivals = response.getArrivalInfo(); + assertNotNull(arrivals); + assertTrue(arrivals.length > 0); + assertNull(arrivals[0].getFrequency()); + } } diff --git a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ObaArrivalInfoTest.java b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ObaArrivalInfoTest.java index f058bfddd4..7a30174bc4 100644 --- a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ObaArrivalInfoTest.java +++ b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ObaArrivalInfoTest.java @@ -181,4 +181,32 @@ public void testGetOccupancy_Null() { assertNull(info.getHistoricalOccupancy()); assertNull(info.getOccupancyStatus()); } + + @Test + public void testFrequency_Present() { + String json = "{\"frequency\":{\"startTime\":1456747200000," + + "\"headway\":600,\"endTime\":1456808400000}}"; + ObaArrivalInfo info = JacksonSerializer.getInstance() + .deserializeFromResponse(json, ObaArrivalInfo.class); + assertNotNull(info.getFrequency()); + assertEquals(1456747200000L, info.getFrequency().getStartTime()); + assertEquals(1456808400000L, info.getFrequency().getEndTime()); + assertEquals(600, info.getFrequency().getHeadway()); + } + + @Test + public void testFrequency_Null() { + String json = "{\"frequency\":null}"; + ObaArrivalInfo info = JacksonSerializer.getInstance() + .deserializeFromResponse(json, ObaArrivalInfo.class); + assertNull(info.getFrequency()); + } + + @Test + public void testFrequency_Missing() { + String json = "{}"; + ObaArrivalInfo info = JacksonSerializer.getInstance() + .deserializeFromResponse(json, ObaArrivalInfo.class); + assertNull(info.getFrequency()); + } } diff --git a/onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/UIUtilTest.java b/onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/UIUtilTest.java index 2654c20ce7..0954289322 100644 --- a/onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/UIUtilTest.java +++ b/onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/UIUtilTest.java @@ -49,7 +49,9 @@ import org.onebusaway.android.util.ArrivalInfoUtils; import org.onebusaway.android.util.UIUtils; +import java.text.DateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -948,6 +950,50 @@ public void testGetTransparentColor() { assertEquals(alpha, newAlpha); } + /** + * Verifies the user-visible status label for frequency-based ("Every N mins") arrivals, + * which is the rendering path that issue #430 is about. Uses the USF Bull Runner fixture + * and exercises both branches of {@link ArrivalInfo#getStatusText()} - the "until" label + * (now inside the frequency window) and the "from" label (now before the window starts). + */ + @Test + public void testFrequencyStatusLabels() { + // ObaTestCase.before() sets the Puget Sound API URL; the URI map resolves the USF + // request by path, so no setCustomApiUrl / region override is needed here. + ObaArrivalInfoResponse response = + new ObaArrivalInfoRequest.Builder(getTargetContext(), + "USF Bull Runner_203").build().call(); + assertOK(response); + + ObaArrivalInfo[] arrivals = response.getArrivalInfo(); + assertNotNull(arrivals); + assertTrue(arrivals.length > 0); + + ObaArrivalInfo arrival = arrivals[0]; + ObaArrivalInfo.Frequency frequency = arrival.getFrequency(); + assertNotNull(frequency); + + // headway of 600 seconds renders as 10 minutes; the time is formatted exactly as + // ArrivalInfo formats it, so the assertion is locale/timezone-independent. + int headwayAsMinutes = (int) (frequency.getHeadway() / 60); + DateFormat formatter = DateFormat.getTimeInstance(DateFormat.SHORT); + + // "until" branch - the fixture's currentTime falls inside the frequency window + long nowDuring = response.getCurrentTime(); + assertTrue(nowDuring >= frequency.getStartTime() && nowDuring < frequency.getEndTime()); + ArrivalInfo during = new ArrivalInfo(getTargetContext(), arrival, nowDuring, true); + String expectedUntil = getTargetContext().getString(R.string.stop_info_frequency_until, + headwayAsMinutes, formatter.format(new Date(frequency.getEndTime()))); + assertEquals(expectedUntil, during.getStatusText()); + + // "from" branch - now is before the frequency window starts + long nowBefore = frequency.getStartTime() - 60 * 1000; + ArrivalInfo before = new ArrivalInfo(getTargetContext(), arrival, nowBefore, true); + String expectedFrom = getTargetContext().getString(R.string.stop_info_frequency_from, + headwayAsMinutes, formatter.format(new Date(frequency.getStartTime()))); + assertEquals(expectedFrom, before.getStatusText()); + } + private String formatTime(long time) { return UIUtils.formatTime(getTargetContext(), time); } diff --git a/onebusaway-android/src/androidTest/res/raw/arrivals_and_departures_for_stop_usf_frequency.json b/onebusaway-android/src/androidTest/res/raw/arrivals_and_departures_for_stop_usf_frequency.json new file mode 100644 index 0000000000..c7410b2d0c --- /dev/null +++ b/onebusaway-android/src/androidTest/res/raw/arrivals_and_departures_for_stop_usf_frequency.json @@ -0,0 +1 @@ +{"currentTime":1456780082393,"text":"OK","data":{"references":{"stops":[{"id":"USF Bull Runner_203","lon":-82.4161291122,"direction":"","locationType":0,"name":"Center for Transportation Research","wheelchairBoarding":"UNKNOWN","routeIds":["USF Bull Runner_D","USF Bull Runner_E"],"code":"203","lat":28.0580728714},{"id":"USF Bull Runner_204","lon":-82.4157978594,"direction":"","locationType":0,"name":"Research & Development","wheelchairBoarding":"UNKNOWN","routeIds":["USF Bull Runner_A","USF Bull Runner_D"],"code":"204","lat":28.0577829169}],"situations":[],"trips":[{"id":"USF Bull Runner_11","shapeId":"USF Bull Runner_4","tripShortName":"","directionId":"","serviceId":"USF Bull Runner_Mo","blockId":"USF Bull Runner_11","routeShortName":"","tripHeadsign":"Gold Campus Loop","routeId":"USF Bull Runner_E","timeZone":""},{"id":"USF Bull Runner_8","shapeId":"USF Bull Runner_3","tripShortName":"","directionId":"","serviceId":"USF Bull Runner_Mo","blockId":"USF Bull Runner_8","routeShortName":"","tripHeadsign":"Red Off-Campus West","routeId":"USF Bull Runner_D","timeZone":""}],"routes":[{"id":"USF Bull Runner_D","textColor":"FFFFFF","color":"F70505","description":"","longName":"Red Off-Campus West","shortName":"D","type":3,"agencyId":"USF Bull Runner","url":"http://usfweb2.usf.edu/parking_services/BullRunnerRoutesStops.htm"},{"id":"USF Bull Runner_E","textColor":"FFFFFF","color":"D4BA13","description":"","longName":"Gold Campus Loop","shortName":"E","type":3,"agencyId":"USF Bull Runner","url":"http://usfweb2.usf.edu/parking_services/BullRunnerRoutesStops.htm"}],"agencies":[{"id":"USF Bull Runner","privateService":false,"phone":"","timezone":"America/New_York","disclaimer":"","name":"USF Bull Runner","lang":"en","url":"http://www.usf.edu/administrative-services/parking"}]},"entry":{"situationIds":[],"stopId":"USF Bull Runner_203","arrivalsAndDepartures":[{"serviceDate":1456722000000,"numberOfStopsAway":0,"vehicleId":"","lastUpdateTime":0,"routeId":"USF Bull Runner_E","frequency":{"startTime":1456747200000,"headway":600,"endTime":1456808400000},"stopSequence":13,"scheduledDepartureInterval":null,"routeShortName":"E","arrivalEnabled":true,"distanceFromStop":0,"scheduledArrivalTime":1456780382378,"status":"default","tripId":"USF Bull Runner_11","routeLongName":"Gold Campus Loop","tripHeadsign":"Gold Campus Loop","predicted":false,"predictedArrivalTime":0,"departureEnabled":true,"scheduledArrivalInterval":null,"predictedDepartureTime":0,"situationIds":[],"stopId":"USF Bull Runner_203","tripStatus":null,"scheduledDepartureTime":1456780382378,"blockTripSequence":0,"predictedArrivalInterval":null,"predictedDepartureInterval":null},{"serviceDate":1456722000000,"numberOfStopsAway":0,"vehicleId":"","lastUpdateTime":0,"routeId":"USF Bull Runner_D","frequency":{"startTime":1456747200000,"headway":600,"endTime":1456808400000},"stopSequence":18,"scheduledDepartureInterval":null,"routeShortName":"D","arrivalEnabled":true,"distanceFromStop":0,"scheduledArrivalTime":1456780382378,"status":"default","tripId":"USF Bull Runner_8","routeLongName":"Red Off-Campus West","tripHeadsign":"Red Off-Campus West","predicted":false,"predictedArrivalTime":0,"departureEnabled":true,"scheduledArrivalInterval":null,"predictedDepartureTime":0,"situationIds":[],"stopId":"USF Bull Runner_203","tripStatus":null,"scheduledDepartureTime":1456780382378,"blockTripSequence":0,"predictedArrivalInterval":null,"predictedDepartureInterval":null}],"nearbyStopIds":["USF Bull Runner_204"]}},"code":200,"version":2} diff --git a/onebusaway-android/src/androidTest/res/raw/urimap.json b/onebusaway-android/src/androidTest/res/raw/urimap.json index d4c6b62f64..9a16b28e11 100644 --- a/onebusaway-android/src/androidTest/res/raw/urimap.json +++ b/onebusaway-android/src/androidTest/res/raw/urimap.json @@ -22,6 +22,7 @@ "/api/where/arrivals-and-departures-for-stop/MTS_11671.json": "arrivals_and_departures_for_stop_mts_11671_filter_route_alerts", "/api/where/arrivals-and-departures-for-stop/MTS_9999.json": "sdmts_arrivals_and_departures_for_stop_no_end_time", "/api/where/arrivals-and-departures-for-stop/1_10020_occupancy.json": "arrivals_and_departures_for_stop_1_10020_occupancy", + "/api/where/arrivals-and-departures-for-stop/USF%20Bull%20Runner_203.json": "arrivals_and_departures_for_stop_usf_frequency", "/api/api/where/agencies-with-coverage.json": "agencies_with_coverage_tampa", "/api/api/where/arrivals-and-departures-for-stop/Hillsborough%20Area%20Regional%20Transit_3105.json": "arrivals_and_departures_for_stop_hart_3105",