package org.opentripplanner.analyst.scenario;
import junit.framework.TestCase;
import org.junit.Test;
import org.onebusaway.gtfs.model.Agency;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.Route;
import org.onebusaway.gtfs.model.Stop;
import org.onebusaway.gtfs.model.StopTime;
import org.onebusaway.gtfs.model.Trip;
import org.opentripplanner.model.StopPattern;
import org.opentripplanner.routing.edgetype.TripPattern;
import org.opentripplanner.routing.trippattern.Deduplicator;
import org.opentripplanner.routing.trippattern.FrequencyEntry;
import org.opentripplanner.routing.trippattern.TripTimes;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* Tests for various timetable filters
*/
public class TimetableFilterTest extends TestCase {
private TripPattern pattern, metroPattern;
private Trip trip, trip2, metroTrip;
private TripTimes times, metroTimes;
private FrequencyEntry frequencyEntry;
private Stop[] stops;
private Agency agency;
private Route route, metro;
/* ROUTE REMOVAL (also matching) */
/** test that routes that should be removed are */
@Test
public void testRouteRemoval () {
RemoveTrip rt = new RemoveTrip();
rt.agencyId = agency.getId();
rt.routeId = Arrays.asList(route.getId().getId());
assertNull(rt.apply(trip, pattern, times));
assertNull(rt.apply(trip, pattern, frequencyEntry));
}
/** test that routes removed by route type work */
@Test
public void testTripRemovalByRouteType () {
RemoveTrip rt = new RemoveTrip();
rt.agencyId = agency.getId();
rt.routeType = new int[] { com.conveyal.gtfs.model.Route.SUBWAY };
assertNull(rt.apply(metroTrip, metroPattern, metroTimes));
assertNotNull(rt.apply(trip, pattern, times));
}
/** test that routes that should not be removed are not */
@Test
public void testRoutePreservation () {
RemoveTrip rt = new RemoveTrip();
rt.agencyId = agency.getId();
rt.routeId = Arrays.asList("SOMETHING ELSE");
assertEquals(times, rt.apply(trip, pattern, times));
assertEquals(frequencyEntry, rt.apply(trip, pattern, frequencyEntry));
}
/** Test that trips that should be removed are */
@Test
public void testTripRemoval () {
RemoveTrip rt = new RemoveTrip();
rt.agencyId = agency.getId();
rt.tripId = Arrays.asList(trip.getId().getId());
assertNull(rt.apply(trip, pattern, times));
assertNull(rt.apply(trip, pattern, frequencyEntry));
}
/** test that trips that should not be removed are not */
@Test
public void testTripPreservation () {
RemoveTrip rt = new RemoveTrip();
rt.agencyId = agency.getId();
rt.tripId = Arrays.asList("SOMETHING ELSE");
assertEquals(times, rt.apply(trip, pattern, times));
assertEquals(frequencyEntry, rt.apply(trip, pattern, frequencyEntry));
rt.agencyId = "NOT THE AGENCY ID";
rt.tripId = Arrays.asList(trip.getId().getId());
assertEquals(times, rt.apply(trip, pattern, times));
assertEquals(frequencyEntry, rt.apply(trip, pattern, frequencyEntry));
}
/** test a highly specific match */
@Test
public void testSpecificRemoval () {
// route ID and trip ID are supposed to combined with a logical and, ensure that they are.
RemoveTrip rt = new RemoveTrip();
rt.agencyId = agency.getId();
rt.routeId = Arrays.asList(route.getId().getId());
rt.tripId = Arrays.asList(trip.getId().getId());
assertNull(rt.apply(trip, pattern, times));
assertNull(rt.apply(trip, pattern, frequencyEntry));
rt.routeId = Arrays.asList("SOMETHING ELSE");
assertEquals(times, rt.apply(trip, pattern, times));
assertEquals(frequencyEntry, rt.apply(trip, pattern, frequencyEntry));
rt.tripId = Arrays.asList("SOMETHING ELSE");
assertEquals(times, rt.apply(trip, pattern, times));
assertEquals(frequencyEntry, rt.apply(trip, pattern, frequencyEntry));
rt.routeId = Arrays.asList(route.getId().getId());
assertEquals(times, rt.apply(trip, pattern, times));
assertEquals(frequencyEntry, rt.apply(trip, pattern, frequencyEntry));
}
/** Test modification of dwell times */
@Test
public void testDwellTimes () {
AdjustDwellTime adt = new AdjustDwellTime();
adt.routeId = Arrays.asList(route.getId().getId());
adt.agencyId = agency.getId();
adt.stopId = Arrays.asList(stops[0].getId().getId(), stops[2].getId().getId());
adt.dwellTime = 60;
TripTimes tt2 = adt.apply(trip, pattern, times);
assertNotNull(tt2);
assertEquals(times.getArrivalTime(0), tt2.getArrivalTime(0));
assertEquals(60, tt2.getDepartureTime(0) - tt2.getArrivalTime(0));
assertEquals(30, tt2.getDepartureTime(1) - tt2.getArrivalTime(1));
assertEquals(60, tt2.getDepartureTime(2) - tt2.getArrivalTime(2));
assertEquals(30, tt2.getDepartureTime(3) - tt2.getArrivalTime(3));
// make sure we didn't accidentally modify the orignal times
assertEquals(30, times.getDepartureTime(2) - times.getArrivalTime(2));
FrequencyEntry fe2 = adt.apply(trip, pattern, frequencyEntry);
assertNotNull(fe2);
tt2 = fe2.tripTimes;
assertEquals(60, tt2.getDepartureTime(0) - tt2.getArrivalTime(0));
assertEquals(30, tt2.getDepartureTime(1) - tt2.getArrivalTime(1));
assertEquals(60, tt2.getDepartureTime(2) - tt2.getArrivalTime(2));
assertEquals(30, tt2.getDepartureTime(3) - tt2.getArrivalTime(3));
// make sure we didn't accidentally modify the original times
assertEquals(30, frequencyEntry.tripTimes.getDepartureTime(2) - frequencyEntry.tripTimes.getArrivalTime(2));
// wildcard
adt.stopId = null;
tt2 = adt.apply(trip, pattern, times);
assertNotNull(tt2);
assertEquals(times.getArrivalTime(0), tt2.getArrivalTime(0));
assertEquals(60, tt2.getDepartureTime(0) - tt2.getArrivalTime(0));
assertEquals(60, tt2.getDepartureTime(1) - tt2.getArrivalTime(1));
assertEquals(60, tt2.getDepartureTime(2) - tt2.getArrivalTime(2));
assertEquals(60, tt2.getDepartureTime(3) - tt2.getArrivalTime(3));
// test repeated application
adt.stopId = Arrays.asList(stops[2].getId().getId());
adt.dwellTime = 17;
tt2 = adt.apply(trip, pattern, tt2);
assertNotNull(tt2);
assertEquals(times.getArrivalTime(0), tt2.getArrivalTime(0));
assertEquals(60, tt2.getDepartureTime(0) - tt2.getArrivalTime(0));
assertEquals(60, tt2.getDepartureTime(1) - tt2.getArrivalTime(1));
assertEquals(17, tt2.getDepartureTime(2) - tt2.getArrivalTime(2));
assertEquals(60, tt2.getDepartureTime(3) - tt2.getArrivalTime(3));
}
/** test modifying frequencies */
@Test
public void testAdjustHeadway () {
AdjustHeadway ah = new AdjustHeadway();
ah.agencyId = agency.getId();
ah.routeId = Arrays.asList(route.getId().getId());
ah.headway = 120;
// should have no effect on scheduled trips
assertEquals(times, ah.apply(trip, pattern, times));
FrequencyEntry fe2 = ah.apply(trip, pattern, frequencyEntry);
assertNotNull(fe2);
assertEquals(120, fe2.headway);
// make sure we didn't accidentally modify the entry in the graph
assertEquals(600, frequencyEntry.headway);
}
/** test modifying trip patterns */
@Test
public void testSkipStopInMiddle () {
SkipStop ss = new SkipStop();
ss.routeId = Arrays.asList(route.getId().getId());
ss.agencyId = agency.getId();
ss.stopId = Arrays.asList(stops[2].getId().getId());
Collection<TripPattern> result = ss.apply(pattern);
assertEquals(1, result.size());
TripPattern newtp = result.iterator().next();
assertNotSame(pattern, newtp);
// TODO getNumScheduledTrips is zero - why?
assertEquals(2, newtp.scheduledTimetable.tripTimes.size());
assertEquals(2, newtp.scheduledTimetable.frequencyEntries.size());
assertEquals(3, newtp.stopPattern.size);
// make sure the times are correct
assertEquals(pattern.scheduledTimetable.tripTimes.get(0).getDepartureTime(0),
newtp.scheduledTimetable.tripTimes.get(0).getDepartureTime(0));
// after the skipped stop: dwell times should be removed
assertEquals(pattern.scheduledTimetable.tripTimes.get(0).getDepartureTime(3) - 30,
newtp.scheduledTimetable.tripTimes.get(0).getDepartureTime(2));
assertEquals(pattern.stopPattern.stops[3], newtp.stopPattern.stops[2]);
// and for the frequency entry
// make sure the times are correct
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(0),
newtp.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(0));
// after the skipped stop: dwell times should be removed
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(3) - 30,
newtp.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(2));
}
/** test modifying one trip on a trip pattern */
@Test
public void testModifySingleTrip () {
SkipStop ss = new SkipStop();
ss.routeId = Arrays.asList(route.getId().getId());
ss.agencyId = agency.getId();
ss.tripId = Arrays.asList(trip.getId().getId());
ss.stopId = Arrays.asList(stops[2].getId().getId());
Collection<TripPattern> result = ss.apply(pattern);
assertEquals(2, result.size());
Iterator<TripPattern> tpit = result.iterator();
// non-ideal: assuming defined order.
TripPattern newtp = tpit.next();
TripPattern clone = tpit.next();
assertNotSame(pattern, newtp);
assertNotSame(pattern, clone);
assertEquals(1, newtp.scheduledTimetable.tripTimes.size());
assertEquals(1, newtp.scheduledTimetable.frequencyEntries.size());
assertEquals(3, newtp.stopPattern.size);
// make sure the times are correct
assertEquals(pattern.scheduledTimetable.tripTimes.get(0).getDepartureTime(0),
newtp.scheduledTimetable.tripTimes.get(0).getDepartureTime(0));
// after the skipped stop: dwell times should be removed
assertEquals(pattern.scheduledTimetable.tripTimes.get(0).getDepartureTime(3) - 30,
newtp.scheduledTimetable.tripTimes.get(0).getDepartureTime(2));
assertEquals(pattern.stopPattern.stops[3], newtp.stopPattern.stops[2]);
// and for the frequency entry
// make sure the times are correct
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(0),
newtp.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(0));
// after the skipped stop: dwell times should be removed
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(3) - 30,
newtp.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(2));
// make sure the times are correct on the trips that were not modified
assertEquals(pattern.scheduledTimetable.tripTimes.get(0).getDepartureTime(0),
clone.scheduledTimetable.tripTimes.get(0).getDepartureTime(0));
// after the skipped stop: dwell times should be removed
assertEquals(pattern.scheduledTimetable.tripTimes.get(0).getDepartureTime(3),
clone.scheduledTimetable.tripTimes.get(0).getDepartureTime(3));
assertEquals(pattern.stopPattern.stops[3], clone.stopPattern.stops[3]);
// and for the frequency entry
// make sure the times are correct
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(0),
clone.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(0));
// after the skipped stop: dwell times should be removed
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(3),
clone.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(3));
}
@Test
public void testSkipStopsAtStart () {
SkipStop ss = new SkipStop();
ss.routeId = Arrays.asList(route.getId().getId());
ss.agencyId = agency.getId();
ss.stopId = Arrays.asList(stops[0].getId().getId(), stops[1].getId().getId());
Collection<TripPattern> result = ss.apply(pattern);
assertEquals(1, result.size());
TripPattern newtp = result.iterator().next();
assertNotSame(pattern, newtp);
assertEquals(2, newtp.scheduledTimetable.tripTimes.size());
assertEquals(2, newtp.scheduledTimetable.frequencyEntries.size());
assertEquals(2, newtp.stopPattern.size);
// make sure the times are correct
// Note that there should be no dwell compression; the start of the trip should simply be chopped off.
assertEquals(pattern.scheduledTimetable.getTripTimes(0).getDepartureTime(2),
newtp.scheduledTimetable.getTripTimes(0).getDepartureTime(0));
assertEquals(pattern.scheduledTimetable.getTripTimes(0).getDepartureTime(3),
newtp.scheduledTimetable.getTripTimes(0).getDepartureTime(1));
assertEquals(pattern.stopPattern.stops[3], newtp.stopPattern.stops[1]);
// and for the frequency entry
// make sure the times are correct
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(2),
newtp.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(0));
// after the skipped stop: dwell times should be removed
assertEquals(pattern.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(3),
newtp.scheduledTimetable.frequencyEntries.get(0).tripTimes.getDepartureTime(1));
}
@Override
protected void setUp () {
agency = new Agency();
agency.setId("AGENCY");
route = new Route();
route.setType(com.conveyal.gtfs.model.Route.BUS);
route.setShortName("T");
route.setLongName("TEST");
route.setAgency(agency);
route.setId(new AgencyAndId(agency.getId(), "TEST"));
metro = new Route();
metro.setType(com.conveyal.gtfs.model.Route.SUBWAY);
metro.setShortName("M");
metro.setLongName("METRO");
metro.setAgency(agency);
metro.setId(new AgencyAndId(agency.getId(), "METRO"));
trip = new Trip();
trip.setRoute(route);
trip.setId(new AgencyAndId(agency.getId(), "TRIP"));
trip2 = new Trip();
trip2.setRoute(route);
trip2.setId(new AgencyAndId(agency.getId(), "TRIP2"));
stops = new Stop[4];
for (int i = 0; i < stops.length; i++) {
Stop s = new Stop();
s.setLat(-122.123);
s.setLon(37.363 + i * 0.001);
s.setId(new AgencyAndId(agency.getId(), "" + i));
stops[i] = s;
}
List<StopTime> stopTimes = makeStopTimes(trip);
StopPattern sp = new StopPattern(stopTimes);
pattern = new TripPattern(route, sp);
// make a triptimes
times = makeTripTimes(trip, stopTimes);
pattern.scheduledTimetable.addTripTimes(times);
pattern.scheduledTimetable.addTripTimes(makeTripTimes(trip2, makeStopTimes(trip2)));
// ten-minute frequency
frequencyEntry = new FrequencyEntry(7 * 3600, 12 * 3600, 600, false, makeTripTimes(trip, makeStopTimes(trip)));
pattern.scheduledTimetable.addFrequencyEntry(frequencyEntry);
pattern.scheduledTimetable.addFrequencyEntry(new FrequencyEntry(7 * 3600, 12 * 3600, 600, false, makeTripTimes(trip2, makeStopTimes(trip2))));
metroTrip = new Trip();
metroTrip.setRoute(metro);
metroTrip.setId(new AgencyAndId(agency.getId(), "TRIP"));
stopTimes = makeStopTimes(metroTrip);
sp = new StopPattern(stopTimes);
metroPattern = new TripPattern(metro, sp);
metroTimes = makeTripTimes(metroTrip, stopTimes);
metroPattern.scheduledTimetable.addTripTimes(metroTimes);
}
/** Make up some trip times. Dwell is 30s, hop is 120s */
private TripTimes makeTripTimes (Trip trip, List<StopTime> stopTimes) {
return new TripTimes(trip, makeStopTimes(trip), new Deduplicator());
}
private List<StopTime> makeStopTimes (Trip trip) {
StopTime[] stopTimes = new StopTime[stops.length];
int cumulativeTime = 7 * 3600;
for (int i = 0; i < stops.length; i++) {
Stop stop = stops[i];
StopTime st = new StopTime();
st.setStop(stop);
st.setArrivalTime(cumulativeTime);
// dwell time is 30 secs
cumulativeTime += 30;
st.setDepartureTime(cumulativeTime);
// hop time is 2 minutes
cumulativeTime += 120;
st.setPickupType(StopPattern.PICKDROP_SCHEDULED);
st.setDropOffType(StopPattern.PICKDROP_SCHEDULED);
st.setTrip(trip);
stopTimes[i] = st;
}
return Arrays.asList(stopTimes);
}
}