-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
211 additions
and
0 deletions.
There are no files selected for viewing
112 changes: 112 additions & 0 deletions
112
.../main/java/org/mobilitydata/gtfsvalidator/validator/ContinuousPickupDropOffValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package org.mobilitydata.gtfsvalidator.validator; | ||
|
||
import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.ERROR; | ||
|
||
import javax.inject.Inject; | ||
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice; | ||
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; | ||
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; | ||
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; | ||
import org.mobilitydata.gtfsvalidator.table.*; | ||
import org.mobilitydata.gtfsvalidator.type.GtfsTime; | ||
|
||
/** | ||
* Validates that if `routes.continuous_pickup` or `routes.continuous_drop_off` are included, then | ||
* `stop_times.start_pickup_drop_off_window` or `stop_times.end_pickup_drop_off_window` are not | ||
* defined for any trip of this route. | ||
* | ||
* <p>Generated notice: {@link ForbiddenContinuousPickupDropOffNotice}. | ||
*/ | ||
@GtfsValidator | ||
public class ContinuousPickupDropOffValidator extends FileValidator { | ||
private final GtfsRouteTableContainer routeTable; | ||
private final GtfsTripTableContainer tripTable; | ||
private final GtfsStopTimeTableContainer stopTimeTable; | ||
|
||
@Inject | ||
public ContinuousPickupDropOffValidator( | ||
GtfsRouteTableContainer routeTable, | ||
GtfsTripTableContainer tripTable, | ||
GtfsStopTimeTableContainer stopTimeTable) { | ||
this.routeTable = routeTable; | ||
this.tripTable = tripTable; | ||
this.stopTimeTable = stopTimeTable; | ||
} | ||
|
||
@Override | ||
public void validate(NoticeContainer noticeContainer) { | ||
for (GtfsRoute route : routeTable.getEntities()) { | ||
boolean continuous = | ||
(route.continuousPickup() == GtfsContinuousPickupDropOff.ALLOWED | ||
|| route.continuousPickup() == GtfsContinuousPickupDropOff.MUST_PHONE | ||
|| route.continuousPickup() == GtfsContinuousPickupDropOff.ON_REQUEST_TO_DRIVER) | ||
|| (route.continuousDropOff() == GtfsContinuousPickupDropOff.ALLOWED | ||
|| route.continuousDropOff() == GtfsContinuousPickupDropOff.MUST_PHONE | ||
|| route.continuousDropOff() == GtfsContinuousPickupDropOff.ON_REQUEST_TO_DRIVER); | ||
if (!continuous) { | ||
continue; | ||
} | ||
for (GtfsTrip trip : tripTable.byRouteId(route.routeId())) { | ||
for (GtfsStopTime stopTime : stopTimeTable.byTripId(trip.tripId())) { | ||
if (stopTime.hasStartPickupDropOffWindow() || stopTime.hasEndPickupDropOffWindow()) { | ||
noticeContainer.addValidationNotice( | ||
new ForbiddenContinuousPickupDropOffNotice( | ||
route.csvRowNumber(), | ||
trip.tripId(), | ||
stopTime.csvRowNumber(), | ||
stopTime.startPickupDropOffWindow(), | ||
stopTime.endPickupDropOffWindow())); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public boolean shouldCallValidate() { | ||
if (routeTable != null && stopTimeTable != null) { | ||
return routeTable.hasColumn(GtfsRoute.CONTINUOUS_PICKUP_FIELD_NAME) | ||
|| routeTable.hasColumn(GtfsRoute.CONTINUOUS_DROP_OFF_FIELD_NAME) | ||
&& (stopTimeTable.hasColumn(GtfsStopTime.START_PICKUP_DROP_OFF_WINDOW_FIELD_NAME) | ||
|| stopTimeTable.hasColumn(GtfsStopTime.END_PICKUP_DROP_OFF_WINDOW_FIELD_NAME)); | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Continuous pickup or drop-off are forbidden when routes.continuous_pickup or | ||
* routes.continuous_drop_off are 0, 2 or 3 and stop_times.start_pickup_drop_off_window or | ||
* stop_times.end_pickup_drop_off_window are defined for any trip of this route. | ||
*/ | ||
@GtfsValidationNotice(severity = ERROR) | ||
public static class ForbiddenContinuousPickupDropOffNotice extends ValidationNotice { | ||
/** The row number of the route in the `routes.txt` file. */ | ||
private final int routeCsvRowNumber; | ||
|
||
/** The ID of the trip. */ | ||
private final String tripId; | ||
|
||
/** The row number of the stop time in the `stop_times.txt` file. */ | ||
private final int stopTimeCsvRowNumber; | ||
|
||
/** The start time of the pickup/drop-off window. */ | ||
private final GtfsTime startPickupDropOffWindow; | ||
|
||
/** The end time of the pickup/drop-off window. */ | ||
private final GtfsTime endPickupDropOffWindow; | ||
|
||
public ForbiddenContinuousPickupDropOffNotice( | ||
int routeCsvRowNumber, | ||
String tripId, | ||
int stopTimesCsvRowNumber, | ||
GtfsTime startPickupDropOffWindow, | ||
GtfsTime endPickupDropOffWindow) { | ||
this.routeCsvRowNumber = routeCsvRowNumber; | ||
this.tripId = tripId; | ||
this.stopTimeCsvRowNumber = stopTimesCsvRowNumber; | ||
this.startPickupDropOffWindow = startPickupDropOffWindow; | ||
this.endPickupDropOffWindow = endPickupDropOffWindow; | ||
} | ||
} | ||
} |
99 changes: 99 additions & 0 deletions
99
...t/java/org/mobilitydata/gtfsvalidator/validator/ContinuousPickupDropOffValidatorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package org.mobilitydata.gtfsvalidator.validator; | ||
|
||
import static com.google.common.truth.Truth.assertThat; | ||
|
||
import java.util.List; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.JUnit4; | ||
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; | ||
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; | ||
import org.mobilitydata.gtfsvalidator.table.*; | ||
import org.mobilitydata.gtfsvalidator.type.GtfsTime; | ||
|
||
@RunWith(JUnit4.class) | ||
public class ContinuousPickupDropOffValidatorTest { | ||
|
||
private static List<ValidationNotice> generateNotices( | ||
List<GtfsRoute> routes, List<GtfsTrip> trips, List<GtfsStopTime> stopTimes) { | ||
NoticeContainer noticeContainer = new NoticeContainer(); | ||
GtfsRouteTableContainer routeTable = | ||
GtfsRouteTableContainer.forEntities(routes, noticeContainer); | ||
GtfsTripTableContainer tripTable = GtfsTripTableContainer.forEntities(trips, noticeContainer); | ||
GtfsStopTimeTableContainer stopTimeTable = | ||
GtfsStopTimeTableContainer.forEntities(stopTimes, noticeContainer); | ||
new ContinuousPickupDropOffValidator(routeTable, tripTable, stopTimeTable) | ||
.validate(noticeContainer); | ||
return noticeContainer.getValidationNotices(); | ||
} | ||
|
||
@Test | ||
public void continuousPickupWithPickupDropOffWindowShouldGenerateNotice() { | ||
List<ValidationNotice> notices = | ||
generateNotices( | ||
List.of( | ||
new GtfsRoute.Builder() | ||
.setCsvRowNumber(1) | ||
.setRouteId("route1") | ||
.setContinuousPickup(2) | ||
.build()), | ||
List.of( | ||
new GtfsTrip.Builder() | ||
.setCsvRowNumber(2) | ||
.setTripId("trip1") | ||
.setRouteId("route1") | ||
.build()), | ||
List.of( | ||
new GtfsStopTime.Builder() | ||
.setCsvRowNumber(3) | ||
.setTripId("trip1") | ||
.setStartPickupDropOffWindow(GtfsTime.fromString("08:00:00")) | ||
.setEndPickupDropOffWindow(GtfsTime.fromString("09:00:00")) | ||
.build())); | ||
assertThat(notices) | ||
.containsExactly( | ||
new ContinuousPickupDropOffValidator.ForbiddenContinuousPickupDropOffNotice( | ||
1, "trip1", 3, GtfsTime.fromString("08:00:00"), GtfsTime.fromString("09:00:00"))); | ||
} | ||
|
||
@Test | ||
public void noContinuousPickupOrDropOffShouldNotGenerateNotice() { | ||
List<ValidationNotice> notices = | ||
generateNotices( | ||
List.of(new GtfsRoute.Builder().setCsvRowNumber(1).setRouteId("route1").build()), | ||
List.of( | ||
new GtfsTrip.Builder() | ||
.setCsvRowNumber(2) | ||
.setTripId("trip1") | ||
.setRouteId("route1") | ||
.build()), | ||
List.of( | ||
new GtfsStopTime.Builder() | ||
.setCsvRowNumber(3) | ||
.setTripId("trip1") | ||
.setStartPickupDropOffWindow(GtfsTime.fromString("08:00:00")) | ||
.build())); | ||
assertThat(notices).isEmpty(); | ||
} | ||
|
||
@Test | ||
public void continuousPickupAndDropOffWithoutPickupDropOffWindowShouldNotGenerateNotice() { | ||
List<ValidationNotice> notices = | ||
generateNotices( | ||
List.of( | ||
new GtfsRoute.Builder() | ||
.setCsvRowNumber(1) | ||
.setRouteId("route1") | ||
.setContinuousPickup(1) | ||
.setContinuousDropOff(1) | ||
.build()), | ||
List.of( | ||
new GtfsTrip.Builder() | ||
.setCsvRowNumber(2) | ||
.setTripId("trip1") | ||
.setRouteId("route1") | ||
.build()), | ||
List.of(new GtfsStopTime.Builder().setCsvRowNumber(3).setTripId("trip1").build())); | ||
assertThat(notices).isEmpty(); | ||
} | ||
} |