Skip to content

Commit b491d59

Browse files
authored
Merge d5c7f77 into 9badbe8
2 parents 9badbe8 + d5c7f77 commit b491d59

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.mobilitydata.gtfsvalidator.validator;
2+
3+
import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.ERROR;
4+
5+
import javax.inject.Inject;
6+
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice;
7+
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
8+
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
9+
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
10+
import org.mobilitydata.gtfsvalidator.table.GtfsPickupDropOff;
11+
import org.mobilitydata.gtfsvalidator.table.GtfsStopTime;
12+
import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer;
13+
14+
/**
15+
* Validates `stop_times.start_pickup_dropoff_window`, `stop_times.end_pickup_dropoff_window`,
16+
* `stop_times.pickup_type`, and `stop_times.drop_off_type` for a single `GtfsStopTime`.
17+
*
18+
* <p>Generated notices:
19+
*
20+
* <ul>
21+
* <li>{@link MissingStopTimesRecordNotice}
22+
* </ul>
23+
*/
24+
@GtfsValidator
25+
public class StopTimesRecordValidator extends FileValidator {
26+
private final GtfsStopTimeTableContainer stopTimeTable;
27+
28+
@Inject
29+
public StopTimesRecordValidator(GtfsStopTimeTableContainer stopTimeTable) {
30+
this.stopTimeTable = stopTimeTable;
31+
}
32+
33+
@Override
34+
public void validate(NoticeContainer noticeContainer) {
35+
for (GtfsStopTime entity : stopTimeTable.getEntities()) {
36+
if (entity.hasStartPickupDropOffWindow()
37+
&& entity.hasEndPickupDropOffWindow()
38+
&& entity.pickupType() == GtfsPickupDropOff.MUST_PHONE
39+
&& entity.dropOffType() == GtfsPickupDropOff.MUST_PHONE) {
40+
int tripStopCount = stopTimeTable.byTripId(entity.tripId()).size();
41+
if (tripStopCount == 1) {
42+
noticeContainer.addValidationNotice(
43+
new MissingStopTimesRecordNotice(
44+
entity.csvRowNumber(),
45+
entity.tripId(),
46+
entity.locationGroupId(),
47+
entity.locationId()));
48+
}
49+
}
50+
}
51+
}
52+
53+
@Override
54+
public boolean shouldCallValidate() {
55+
if (stopTimeTable != null) {
56+
return stopTimeTable.hasColumn(GtfsStopTime.START_PICKUP_DROP_OFF_WINDOW_FIELD_NAME)
57+
&& stopTimeTable.hasColumn(GtfsStopTime.END_PICKUP_DROP_OFF_WINDOW_FIELD_NAME)
58+
&& stopTimeTable.hasColumn(GtfsStopTime.PICKUP_TYPE_FIELD_NAME)
59+
&& stopTimeTable.hasColumn(GtfsStopTime.DROP_OFF_TYPE_FIELD_NAME);
60+
} else {
61+
return false;
62+
}
63+
}
64+
65+
/**
66+
* Only one stop_times record is found where two are required.
67+
*
68+
* <p>Travel within the same location group or GeoJSON location requires two records in
69+
* stop_times.txt with the same location_group_id or location_id.
70+
*/
71+
@GtfsValidationNotice(severity = ERROR)
72+
public static class MissingStopTimesRecordNotice extends ValidationNotice {
73+
/** The row of the faulty record. */
74+
private final long csvRowNumber;
75+
76+
/** The `tripId` of the faulty record. */
77+
private final String tripId;
78+
79+
/** The `locationGroupId` of the faulty record. */
80+
private final String locationGroupId;
81+
82+
/** The `locationId` of the faulty record. */
83+
private final String locationId;
84+
85+
public MissingStopTimesRecordNotice(
86+
long csvRowNumber, String tripId, String locationGroupId, String locationId) {
87+
this.csvRowNumber = csvRowNumber;
88+
this.tripId = tripId;
89+
this.locationGroupId = locationGroupId;
90+
this.locationId = locationId;
91+
}
92+
}
93+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.mobilitydata.gtfsvalidator.validator;
2+
3+
import static com.google.common.truth.Truth.assertThat;
4+
5+
import com.google.common.collect.ImmutableList;
6+
import java.util.List;
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
import org.junit.runners.JUnit4;
10+
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
11+
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
12+
import org.mobilitydata.gtfsvalidator.table.GtfsPickupDropOff;
13+
import org.mobilitydata.gtfsvalidator.table.GtfsStopTime;
14+
import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer;
15+
import org.mobilitydata.gtfsvalidator.type.GtfsTime;
16+
17+
@RunWith(JUnit4.class)
18+
public class StopTimesRecordValidatorTest {
19+
20+
public static GtfsStopTime createStopTime(
21+
int csvRowNumber,
22+
String tripId,
23+
String locationGroupId,
24+
String locationId,
25+
GtfsPickupDropOff pickupType,
26+
GtfsPickupDropOff dropOffType,
27+
GtfsTime startWindow,
28+
GtfsTime endWindow) {
29+
return new GtfsStopTime.Builder()
30+
.setCsvRowNumber(csvRowNumber)
31+
.setTripId(tripId)
32+
.setLocationGroupId(locationGroupId)
33+
.setLocationId(locationId)
34+
.setPickupType(pickupType)
35+
.setDropOffType(dropOffType)
36+
.setStartPickupDropOffWindow(startWindow)
37+
.setEndPickupDropOffWindow(endWindow)
38+
.build();
39+
}
40+
41+
private static List<ValidationNotice> generateNotices(List<GtfsStopTime> stopTimes) {
42+
NoticeContainer noticeContainer = new NoticeContainer();
43+
GtfsStopTimeTableContainer stopTimeTable =
44+
GtfsStopTimeTableContainer.forEntities(stopTimes, noticeContainer);
45+
new StopTimesRecordValidator(stopTimeTable).validate(noticeContainer);
46+
return noticeContainer.getValidationNotices();
47+
}
48+
49+
@Test
50+
public void containsStopTimesRecordShouldNotGenerateNotice1() {
51+
assertThat(
52+
generateNotices(
53+
ImmutableList.of(
54+
createStopTime(
55+
1,
56+
"trip1",
57+
"locationGroupId1",
58+
"locationId1",
59+
GtfsPickupDropOff.ALLOWED,
60+
GtfsPickupDropOff.ALLOWED,
61+
GtfsTime.fromString("08:00:00"),
62+
GtfsTime.fromString("09:00:00")))))
63+
.isEmpty();
64+
}
65+
66+
@Test
67+
public void missingStopTimesRecordShouldGenerateNotice() {
68+
assertThat(
69+
generateNotices(
70+
ImmutableList.of(
71+
createStopTime(
72+
1,
73+
"trip2",
74+
"locationGroupId1",
75+
"locationId1",
76+
GtfsPickupDropOff.MUST_PHONE,
77+
GtfsPickupDropOff.MUST_PHONE,
78+
GtfsTime.fromString("08:00:00"),
79+
GtfsTime.fromString("09:00:00")))))
80+
.containsExactly(
81+
new StopTimesRecordValidator.MissingStopTimesRecordNotice(
82+
1, "trip2", "locationGroupId1", "locationId1"));
83+
}
84+
}

0 commit comments

Comments
 (0)