From 0fcaf9e2f73a937e0e461a8db434743227598055 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:52:09 -0500 Subject: [PATCH 01/43] push for diff --- .../validator/ShapeUsageValidator.java | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java index 452b76efab..a56cfc34c8 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java @@ -28,8 +28,12 @@ import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeSchema; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeSchema; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsTrip; import org.mobilitydata.gtfsvalidator.table.GtfsTripSchema; import org.mobilitydata.gtfsvalidator.table.GtfsTripTableContainer; +import org.mobilitydata.gtfsvalidator.validator.ShapeUsageValidator.UnusedShapeNotice; /** * Validates that every shape in "shapes.txt" is used by some trip from "trips.txt" @@ -75,7 +79,7 @@ public void validate(NoticeContainer noticeContainer) { url = "https://gtfs.org/resources/gtfs-schedule-feature-guides/shapes/#shapes-data-guidance") }) - static class UnusedShapeNotice extends ValidationNotice { + static class !MissingRecommendedFileNotice extends ValidationNotice { /** The faulty record's id. */ private final String shapeId; @@ -83,9 +87,38 @@ static class UnusedShapeNotice extends ValidationNotice { /** The row number of the faulty record. */ private final int csvRowNumber; - UnusedShapeNotice(String shapeId, int csvRowNumber) { + MissingRecommendedFileNotice(String shapeId, int csvRowNumber) { this.shapeId = shapeId; this.csvRowNumber = csvRowNumber; } } + + /** + * Validates that every trip in "trips.txt" is used by at least two stops from "stop_times.txt" + * + *

Generated notice: {@link MissingRecommendedFileNotice}. + */ + + /** + * Trips must have more than one stop to be usable. + * + * A trip must visit more than one stop in `stop_times.txt` to be usable by passengers for boarding and alighting. + */ + @GtfsValidationNotice( + severity = WARNING, + files = @FileRefs({GtfsStopTimeSchema.class, GtfsTripSchema.class}), + ) + + static class MissingRecommendedFileNotice extends ValidationNotice { + /** The row number of the faulty record. */ + private final int csvRowNumber; + + /** The faulty record's id. */ + private final String tripId; + + MissingRecommendedFileNotice(int csvRowNumber, String tripId) { + this.csvRowNumber = csvRowNumber; + this.tripId = tripId; + } + } } From ee49572efd7e4fb4ba16ab27e8cabe7ed0d6c670 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:10:14 -0500 Subject: [PATCH 02/43] add to own file --- .../validator/MissingShapesFileValidator.java | 68 +++++++++++++++++++ .../validator/ShapeUsageValidator.java | 36 ++-------- 2 files changed, 72 insertions(+), 32 deletions(-) create mode 100644 main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java new file mode 100644 index 0000000000..a517cbd34e --- /dev/null +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -0,0 +1,68 @@ +package org.mobilitydata.gtfsvalidator.validator; + +import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.WARNING; + +import javax.inject.Inject; + +import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice; +import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice.FileRefs; +import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; +import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; +import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeSchema; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsShape; +import org.mobilitydata.gtfsvalidator.table.GtfsTripSchema; +import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; + + /** + * Validates that the feed has either a `shapes.txt` file, or uses zone-based DRT or fixed-stops DRT. + * + *

Generated notice: {@link MissingRecommendedFileNotice}. + */ +@GtfsValidator +public class MissingShapesFileValidator extends FileValidator { + private final GtfsShapeTableContainer shapeTable; + private final GtfsStopTimeTableContainer stopTimeTable; + private final GtfsLocationGroupsTableContainer locationGroupsTable; + + @Inject + MissingShapesFileValidator( + GtfsShapeTableContainer shapeTable, GtfsStopTimeTableContainer stopTimeTable, GtfsLocationGroupsTableContainer locationGroupsTable) { + this.shapeTable = shapeTable; + this.stopTimeTable = stopTimeTable; + this.locationGroupsTable = locationGroupsTable; + } + + @Override + public void validate(NoticeContainer noticeContainer) { + for (GtfsShape shape : shapeTable.getEntities()) { + String shapeId = shape.shapeId(); + if (stopTimeTable.byTripId(shapeId).size() <= 1) { + noticeContainer.addValidationNotice(new MissingRecommendedFileNotice(shape.csvRowNumber(), shapeId)); + } + } + } + + /** + * A feed must have a `shapes.txt` file, and/or use zone-based or fixed-stops DRT to be usable. + */ + @GtfsValidationNotice( + severity = WARNING, + files = @FileRefs({GtfsStopTimeSchema.class, GtfsTripSchema.class}) + ) + + static class MissingRecommendedFileNotice extends ValidationNotice { + /** The row number of the faulty record. */ + private final int csvRowNumber; + + /** The faulty record's id. */ + private final String tripId; + + MissingRecommendedFileNotice(int csvRowNumber, String tripId) { + this.csvRowNumber = csvRowNumber; + this.tripId = tripId; + } + } +} diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java index a56cfc34c8..29c9428100 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java @@ -65,7 +65,7 @@ public void validate(NoticeContainer noticeContainer) { } } - /** + /** * Shape is not used in GTFS file `trips.txt`. * *

All records defined by GTFS `shapes.txt` should be used in `trips.txt`. @@ -79,7 +79,7 @@ public void validate(NoticeContainer noticeContainer) { url = "https://gtfs.org/resources/gtfs-schedule-feature-guides/shapes/#shapes-data-guidance") }) - static class !MissingRecommendedFileNotice extends ValidationNotice { + static class UnusedShapeNotice extends ValidationNotice { /** The faulty record's id. */ private final String shapeId; @@ -87,38 +87,10 @@ static class !MissingRecommendedFileNotice extends ValidationNotice { /** The row number of the faulty record. */ private final int csvRowNumber; - MissingRecommendedFileNotice(String shapeId, int csvRowNumber) { + UnusedShapeNotice(String shapeId, int csvRowNumber) { this.shapeId = shapeId; this.csvRowNumber = csvRowNumber; } } - /** - * Validates that every trip in "trips.txt" is used by at least two stops from "stop_times.txt" - * - *

Generated notice: {@link MissingRecommendedFileNotice}. - */ - - /** - * Trips must have more than one stop to be usable. - * - * A trip must visit more than one stop in `stop_times.txt` to be usable by passengers for boarding and alighting. - */ - @GtfsValidationNotice( - severity = WARNING, - files = @FileRefs({GtfsStopTimeSchema.class, GtfsTripSchema.class}), - ) - - static class MissingRecommendedFileNotice extends ValidationNotice { - /** The row number of the faulty record. */ - private final int csvRowNumber; - - /** The faulty record's id. */ - private final String tripId; - - MissingRecommendedFileNotice(int csvRowNumber, String tripId) { - this.csvRowNumber = csvRowNumber; - this.tripId = tripId; - } - } -} +} \ No newline at end of file From ffbcca5ec168006f770bd7fb1dc5bec749f2f564 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:23:15 -0500 Subject: [PATCH 03/43] add validator functionality --- .../validator/MissingShapesFileValidator.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index a517cbd34e..c4d226e80d 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -12,7 +12,7 @@ import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeSchema; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsShape; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; import org.mobilitydata.gtfsvalidator.table.GtfsTripSchema; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; @@ -37,12 +37,20 @@ public class MissingShapesFileValidator extends FileValidator { @Override public void validate(NoticeContainer noticeContainer) { - for (GtfsShape shape : shapeTable.getEntities()) { - String shapeId = shape.shapeId(); - if (stopTimeTable.byTripId(shapeId).size() <= 1) { - noticeContainer.addValidationNotice(new MissingRecommendedFileNotice(shape.csvRowNumber(), shapeId)); + for (GtfsStopTime stopTime : stopTimeTable.getEntities()) { + String stopId = stopTime.toString(); + Boolean missingShapes = shapeTable.isMissingFile(); + Boolean hasLocationId = stopTimeTable.hasColumn("location_id"); + Boolean hasLocationGroupId = stopTimeTable.hasColumn("location_group_id"); + Boolean hasLocationGroupsRecord = locationGroupsTable.isParsedSuccessfully(); + // Do we not have a shapes.txt file and not have a location_id (required for Zone-Based DRT)? + if (missingShapes && !hasLocationId) { + // Do we not have a record in location_groups.txt and not have a trip in stop_times.txt that references location_group_id (required for Fixed-Stop DRT)? + if (!hasLocationGroupsRecord && !hasLocationGroupId) { + noticeContainer.addValidationNotice(new MissingRecommendedFileNotice(stopTime.csvRowNumber(), stopId)); } } + } } /** From d078d3b446828eec7f550568ba675907ab9b9465 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 4 Mar 2026 10:59:57 -0500 Subject: [PATCH 04/43] half baked test +some lint --- .../validator/MissingShapesFileValidator.java | 30 ++--- .../validator/ShapeUsageValidator.java | 8 +- .../MissingShapesFileValidatorTest.java | 105 ++++++++++++++++++ 3 files changed, 123 insertions(+), 20 deletions(-) create mode 100644 main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index c4d226e80d..35df528432 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -3,21 +3,21 @@ import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.WARNING; import javax.inject.Inject; - import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice.FileRefs; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeSchema; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeSchema; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsTripSchema; -import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; - /** - * Validates that the feed has either a `shapes.txt` file, or uses zone-based DRT or fixed-stops DRT. +/** + * Validates that the feed has either a `shapes.txt` file, or uses zone-based DRT or fixed-stops + * DRT. * *

Generated notice: {@link MissingRecommendedFileNotice}. */ @@ -29,7 +29,9 @@ public class MissingShapesFileValidator extends FileValidator { @Inject MissingShapesFileValidator( - GtfsShapeTableContainer shapeTable, GtfsStopTimeTableContainer stopTimeTable, GtfsLocationGroupsTableContainer locationGroupsTable) { + GtfsShapeTableContainer shapeTable, + GtfsStopTimeTableContainer stopTimeTable, + GtfsLocationGroupsTableContainer locationGroupsTable) { this.shapeTable = shapeTable; this.stopTimeTable = stopTimeTable; this.locationGroupsTable = locationGroupsTable; @@ -45,22 +47,22 @@ public void validate(NoticeContainer noticeContainer) { Boolean hasLocationGroupsRecord = locationGroupsTable.isParsedSuccessfully(); // Do we not have a shapes.txt file and not have a location_id (required for Zone-Based DRT)? if (missingShapes && !hasLocationId) { - // Do we not have a record in location_groups.txt and not have a trip in stop_times.txt that references location_group_id (required for Fixed-Stop DRT)? + // Do we not have a record in location_groups.txt and not have a trip in stop_times.txt that + // references location_group_id (required for Fixed-Stop DRT)? if (!hasLocationGroupsRecord && !hasLocationGroupId) { - noticeContainer.addValidationNotice(new MissingRecommendedFileNotice(stopTime.csvRowNumber(), stopId)); + noticeContainer.addValidationNotice( + new MissingRecommendedFileNotice(stopTime.csvRowNumber(), stopId)); + } } } - } } - /** + /** * A feed must have a `shapes.txt` file, and/or use zone-based or fixed-stops DRT to be usable. */ @GtfsValidationNotice( severity = WARNING, - files = @FileRefs({GtfsStopTimeSchema.class, GtfsTripSchema.class}) - ) - + files = @FileRefs({GtfsStopTimeSchema.class, GtfsTripSchema.class})) static class MissingRecommendedFileNotice extends ValidationNotice { /** The row number of the faulty record. */ private final int csvRowNumber; diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java index 29c9428100..edc2c389ea 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java @@ -28,9 +28,6 @@ import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeSchema; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeSchema; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsTrip; import org.mobilitydata.gtfsvalidator.table.GtfsTripSchema; import org.mobilitydata.gtfsvalidator.table.GtfsTripTableContainer; import org.mobilitydata.gtfsvalidator.validator.ShapeUsageValidator.UnusedShapeNotice; @@ -65,7 +62,7 @@ public void validate(NoticeContainer noticeContainer) { } } - /** + /** * Shape is not used in GTFS file `trips.txt`. * *

All records defined by GTFS `shapes.txt` should be used in `trips.txt`. @@ -92,5 +89,4 @@ static class UnusedShapeNotice extends ValidationNotice { this.csvRowNumber = csvRowNumber; } } - -} \ No newline at end of file +} diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java new file mode 100644 index 0000000000..f2dbc853a1 --- /dev/null +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -0,0 +1,105 @@ +package org.mobilitydata.gtfsvalidator.validator; + +import static org.junit.Assert.assertThat; + +import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; +import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; +import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroups; +import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsLocationType; +import org.mobilitydata.gtfsvalidator.table.GtfsShape; +import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsStop; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; +import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; +import org.mobilitydata.gtfsvalidator.validator.MissingShapesFileValidator.MissingRecommendedFileNotice; + +public class MissingShapesFileValidatorTest { + + private static List createShapeTable( + int rows, double shapeDistTraveled, double lonLat) { + ArrayList shapes = new ArrayList<>(); + for (int i = 0; i < rows; i++) { + shapes.add( + new GtfsShape.Builder() + .setCsvRowNumber(i + 1) + .setShapeId("s" + i) + .setShapePtLat(lonLat) + .setShapePtLon(lonLat) + .setShapePtSequence(0) + .setShapeDistTraveled(shapeDistTraveled + i) + .build()); + } + return shapes; + } + + private static List createStopTimesTable(int rows, double shapeDistTraveled) { + ArrayList stopTimes = new ArrayList<>(); + for (int i = 0; i < rows; i++) { + stopTimes.add( + new GtfsStopTime.Builder() + .setCsvRowNumber(i + 1) + .setTripId("t" + i) + .setStopSequence(0) + .setStopId("st" + i) + .setShapeDistTraveled(shapeDistTraveled + i) + .build()); + } + return stopTimes; + } + + + private static GtfsStop createLocationGroupsTable(int csvRowNumber, GtfsLocationGroups locationGroups) { + return new GtfsStop.Builder() + .setCsvRowNumber(csvRowNumber) + .build(); + } + + @Test + public void testTripDistanceExceedsShapeDistance() { + List notices = + generateNotices( + createStopTimesTable(1, 10.0), + createShapeTable(1, 9.0, 10.0), + createLocationGroupsTable()); + boolean found = + notices.stream() + .anyMatch( + notice -> + notice + instanceof + TripAndShapeDistanceValidator.TripDistanceExceedsShapeDistanceNotice); + assertThat(found).isTrue(); + } + + @Test + public void tripServingOneStopShouldGenerateNotice() { + assertThat( + generateNotices( + ImmutableList.of( + createTrip(1, "route id value", "service id value", "t0"), + createTrip(3, "route id value", "service id value", "t1")), + ImmutableList.of( + createStopTime(0, "t0", "s0", 2), + createStopTime(0, "t1", "s3", 5), + createStopTime(2, "t1", "s4", 9)))) + .containsExactly(new MissingRecommendedFileNotice(1, "t0")); + } + + private static List generateNotices( + List shapes, + List stopTimes, + List locationGroups) { + NoticeContainer noticeContainer = new NoticeContainer(); + new MissingShapesFileValidator( + GtfsShapeTableContainer.forEntities(shapes, noticeContainer), + GtfsStopTimeTableContainer.forEntities(stopTimes, noticeContainer), + GtfsLocationGroupsTableContainer.forEntities(locationGroups, noticeContainer)) + .validate(noticeContainer); + return noticeContainer.getValidationNotices(); + } +} From abadac7d19904a3d9d7648348cc5fb24e05380bc Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:20:19 -0500 Subject: [PATCH 05/43] push up actual notice tests --- .../MissingShapesFileValidatorTest.java | 93 ++++++++++--------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index f2dbc853a1..2a0b7ddf2a 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertThat; -import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; import org.junit.Test; @@ -10,84 +9,90 @@ import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroups; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsLocationType; import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsStop; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; -import org.mobilitydata.gtfsvalidator.validator.MissingShapesFileValidator.MissingRecommendedFileNotice; public class MissingShapesFileValidatorTest { - private static List createShapeTable( - int rows, double shapeDistTraveled, double lonLat) { + private static List createShapeTable(int rows) { ArrayList shapes = new ArrayList<>(); for (int i = 0; i < rows; i++) { - shapes.add( - new GtfsShape.Builder() - .setCsvRowNumber(i + 1) - .setShapeId("s" + i) - .setShapePtLat(lonLat) - .setShapePtLon(lonLat) - .setShapePtSequence(0) - .setShapeDistTraveled(shapeDistTraveled + i) - .build()); + shapes.add(new GtfsShape.Builder().setCsvRowNumber(i + 1).setShapeId("s" + i).build()); } return shapes; } - private static List createStopTimesTable(int rows, double shapeDistTraveled) { + private static List createStopTimesTable( + int rows, String locationGroupId, String locationId) { ArrayList stopTimes = new ArrayList<>(); for (int i = 0; i < rows; i++) { stopTimes.add( new GtfsStopTime.Builder() .setCsvRowNumber(i + 1) - .setTripId("t" + i) - .setStopSequence(0) - .setStopId("st" + i) - .setShapeDistTraveled(shapeDistTraveled + i) + .setLocationGroupId(locationGroupId) + .setLocationId(locationId) .build()); } return stopTimes; } - - private static GtfsStop createLocationGroupsTable(int csvRowNumber, GtfsLocationGroups locationGroups) { - return new GtfsStop.Builder() - .setCsvRowNumber(csvRowNumber) - .build(); + private static List createLocationGroupsTable( + int rows, String groupId, String groupName) { + ArrayList locationGroups = new ArrayList<>(); + for (int i = 0; i < rows; i++) { + locationGroups.add( + new GtfsLocationGroups.Builder() + .setCsvRowNumber(i + 1) + .setLocationGroupId(groupId) + .setLocationGroupName(groupName) + .build()); + } + return locationGroups; } @Test - public void testTripDistanceExceedsShapeDistance() { + public void testShapesFileAndFixedDrtPresent() { List notices = generateNotices( - createStopTimesTable(1, 10.0), - createShapeTable(1, 9.0, 10.0), - createLocationGroupsTable()); + createShapeTable(1), + createStopTimesTable(1, "a", null), + createLocationGroupsTable(1, "b", "testgroup")); boolean found = notices.stream() .anyMatch( notice -> - notice - instanceof - TripAndShapeDistanceValidator.TripDistanceExceedsShapeDistanceNotice); + notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); assertThat(found).isTrue(); } - @Test - public void tripServingOneStopShouldGenerateNotice() { - assertThat( - generateNotices( - ImmutableList.of( - createTrip(1, "route id value", "service id value", "t0"), - createTrip(3, "route id value", "service id value", "t1")), - ImmutableList.of( - createStopTime(0, "t0", "s0", 2), - createStopTime(0, "t1", "s3", 5), - createStopTime(2, "t1", "s4", 9)))) - .containsExactly(new MissingRecommendedFileNotice(1, "t0")); + public void testShapesFileAndZoneBasedDrtPresent() { + List notices = + generateNotices( + createShapeTable(1), + createStopTimesTable(1, null, "c"), + createLocationGroupsTable(1, "d", "t3stgroup")); + boolean found = + notices.stream() + .anyMatch( + notice -> + notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); + assertThat(found).isTrue(); + } + + public void testNoShapesFileAndNoDrtPresent() { + List notices = + generateNotices( + createShapeTable(0), + createStopTimesTable(1, null, null), + createLocationGroupsTable(0, null, null)); + boolean found = + notices.stream() + .anyMatch( + notice -> + notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); + assertThat(found).isTrue(); } private static List generateNotices( From 5caa4e8f35046541cdef4c75939a5238b72aca43 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 19:47:28 -0400 Subject: [PATCH 06/43] fix to asserttrue? --- .../validator/MissingShapesFileValidatorTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 2a0b7ddf2a..a201e6a3b5 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -1,6 +1,6 @@ package org.mobilitydata.gtfsvalidator.validator; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; @@ -64,9 +64,10 @@ public void testShapesFileAndFixedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found).isTrue(); + assertTrue(found); } + @Test public void testShapesFileAndZoneBasedDrtPresent() { List notices = generateNotices( @@ -78,9 +79,10 @@ public void testShapesFileAndZoneBasedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found).isTrue(); + assertTrue(found); } + @Test public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( @@ -92,7 +94,7 @@ public void testNoShapesFileAndNoDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found).isTrue(); + assertTrue(found); } private static List generateNotices( From e457ddc84e4c66787d9c0bb41ee9821638da0b8a Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 19:54:23 -0400 Subject: [PATCH 07/43] assertThat? --- .../validator/MissingShapesFileValidatorTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index a201e6a3b5..750560e853 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -64,7 +64,7 @@ public void testShapesFileAndFixedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertTrue(found); + assertThat(found); } @Test @@ -79,7 +79,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertTrue(found); + assertThat(found); } @Test @@ -94,7 +94,7 @@ public void testNoShapesFileAndNoDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertTrue(found); + assertThat(found); } private static List generateNotices( From 4ca9741255b71f30e4f219b94fa3d70b99b651a2 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:03:19 -0400 Subject: [PATCH 08/43] make the non-errors assertFalse --- .../validator/MissingShapesFileValidatorTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 750560e853..5efb936ac4 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -1,5 +1,6 @@ package org.mobilitydata.gtfsvalidator.validator; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; @@ -64,7 +65,7 @@ public void testShapesFileAndFixedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found); + assertFalse(found); } @Test @@ -79,7 +80,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found); + assertFalse(found); } @Test @@ -94,7 +95,7 @@ public void testNoShapesFileAndNoDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found); + assertTrue(found); } private static List generateNotices( From 13e3475e303de77023b0e0b783ec54f6312b23e7 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:07:28 -0400 Subject: [PATCH 09/43] assertThat --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 5efb936ac4..5a5d0bf320 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -95,7 +95,7 @@ public void testNoShapesFileAndNoDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertTrue(found); + assertThat(found).isTrue(); } private static List generateNotices( From 32a2cfdfc39f453e5f350f3c72edc15bdc82c735 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:09:57 -0400 Subject: [PATCH 10/43] add import --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 5a5d0bf320..17c33f0d1c 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.List; From 4d5f4958c5f72ef0191e4d043347a46b396e1df7 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:15:32 -0400 Subject: [PATCH 11/43] other assertThat import --- .../validator/MissingShapesFileValidatorTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 17c33f0d1c..68aeef73a2 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -2,7 +2,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertThat; + +import static com.google.common.truth.Truth.assertThat; import java.util.ArrayList; import java.util.List; From 95a83c69f3573b2a9bce0df7dada25562af4d1eb Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:21:15 -0400 Subject: [PATCH 12/43] get rid of assertFalse --- .../validator/MissingShapesFileValidatorTest.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 68aeef73a2..c7af26ff1e 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -1,8 +1,5 @@ package org.mobilitydata.gtfsvalidator.validator; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - import static com.google.common.truth.Truth.assertThat; import java.util.ArrayList; @@ -67,11 +64,11 @@ public void testShapesFileAndFixedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertFalse(found); + assertThat(found).isFalse(); } @Test - public void testShapesFileAndZoneBasedDrtPresent() { + public void testShapesFileAndZoneBasedDrtPresent() { List notices = generateNotices( createShapeTable(1), @@ -82,11 +79,11 @@ public void testShapesFileAndZoneBasedDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertFalse(found); + assertThat(found).isFalse(); } @Test - public void testNoShapesFileAndNoDrtPresent() { + public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( createShapeTable(0), From 337b917d22fd3abd62f039d16f9bf0bc27dca344 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:24:19 -0400 Subject: [PATCH 13/43] isFalse --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index c7af26ff1e..cd7b136659 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -94,7 +94,7 @@ public void testNoShapesFileAndNoDrtPresent() { .anyMatch( notice -> notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found).isTrue(); + assertThat(found).isFalse(); } private static List generateNotices( From a1c45244e2bf533c268076d61440cd73926f4279 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:11:04 -0400 Subject: [PATCH 14/43] copilot feedback --- .../validator/MissingShapesFileValidator.java | 57 +++++++++---------- .../validator/ShapeUsageValidator.java | 1 - .../MissingShapesFileValidatorTest.java | 15 +++-- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index 35df528432..5d1cbf3760 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -6,6 +6,7 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice.FileRefs; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; +import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedFileNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; @@ -39,40 +40,36 @@ public class MissingShapesFileValidator extends FileValidator { @Override public void validate(NoticeContainer noticeContainer) { + Boolean missingShapes = shapeTable.isMissingFile(); + Boolean hasLocationId = stopTimeTable.hasColumn("location_id"); + Boolean hasLocationGroupId = stopTimeTable.hasColumn("location_group_id"); + Boolean hasLocationGroupsRecord = + !locationGroupsTable.isMissingFile() && locationGroupsTable.entityCount() > 0; + // Detect DRT usage from the data, not just from column presence. + boolean hasLocationIdInData = false; + boolean hasLocationGroupIdInData = false; for (GtfsStopTime stopTime : stopTimeTable.getEntities()) { - String stopId = stopTime.toString(); - Boolean missingShapes = shapeTable.isMissingFile(); - Boolean hasLocationId = stopTimeTable.hasColumn("location_id"); - Boolean hasLocationGroupId = stopTimeTable.hasColumn("location_group_id"); - Boolean hasLocationGroupsRecord = locationGroupsTable.isParsedSuccessfully(); - // Do we not have a shapes.txt file and not have a location_id (required for Zone-Based DRT)? - if (missingShapes && !hasLocationId) { - // Do we not have a record in location_groups.txt and not have a trip in stop_times.txt that - // references location_group_id (required for Fixed-Stop DRT)? - if (!hasLocationGroupsRecord && !hasLocationGroupId) { - noticeContainer.addValidationNotice( - new MissingRecommendedFileNotice(stopTime.csvRowNumber(), stopId)); - } + if (stopTime.hasLocationId()) { + hasLocationIdInData = true; + } + if (stopTime.hasLocationGroupId()) { + hasLocationGroupIdInData = true; + } + if (hasLocationIdInData && hasLocationGroupIdInData) { + break; } } - } - /** - * A feed must have a `shapes.txt` file, and/or use zone-based or fixed-stops DRT to be usable. - */ - @GtfsValidationNotice( - severity = WARNING, - files = @FileRefs({GtfsStopTimeSchema.class, GtfsTripSchema.class})) - static class MissingRecommendedFileNotice extends ValidationNotice { - /** The row number of the faulty record. */ - private final int csvRowNumber; - - /** The faulty record's id. */ - private final String tripId; - - MissingRecommendedFileNotice(int csvRowNumber, String tripId) { - this.csvRowNumber = csvRowNumber; - this.tripId = tripId; + // Do we not have: a shapes.txt file and not have a location_id (required for Zone-Based DRT), + // and also not have a record in location_groups.txt and not have a trip in stop_times.txt that + // references location_group_id (required for Fixed-Stop DRT)? + if (missingShapes && !hasLocationId && !hasLocationGroupsRecord && !hasLocationGroupId) { + for (GtfsStopTime stopTime : stopTimeTable.getEntities()) { + noticeContainer.addValidationNotice( + new MissingRecommendedFileNotice("shapes.txt")); + // This is a feed-level warning; emit it at most once. + break; + } } } } diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java index edc2c389ea..452b76efab 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/ShapeUsageValidator.java @@ -30,7 +30,6 @@ import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsTripSchema; import org.mobilitydata.gtfsvalidator.table.GtfsTripTableContainer; -import org.mobilitydata.gtfsvalidator.validator.ShapeUsageValidator.UnusedShapeNotice; /** * Validates that every shape in "shapes.txt" is used by some trip from "trips.txt" diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index cd7b136659..9b6dd7a6d9 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -33,6 +33,8 @@ private static List createStopTimesTable( .setCsvRowNumber(i + 1) .setLocationGroupId(locationGroupId) .setLocationId(locationId) + .setTripId(locationGroupId) + .setStopSequence(i + 1) .build()); } return stopTimes; @@ -63,7 +65,7 @@ public void testShapesFileAndFixedDrtPresent() { notices.stream() .anyMatch( notice -> - notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); + notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); } @@ -78,7 +80,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { notices.stream() .anyMatch( notice -> - notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); + notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); } @@ -89,12 +91,13 @@ public void testNoShapesFileAndNoDrtPresent() { createShapeTable(0), createStopTimesTable(1, null, null), createLocationGroupsTable(0, null, null)); - boolean found = + long missingRecommendedFileNoticesCount = notices.stream() - .anyMatch( + .filter( notice -> - notice instanceof MissingShapesFileValidator.MissingRecommendedFileNotice); - assertThat(found).isFalse(); + notice instanceof MissingRecommendedFileNotice) + .count(); + assertThat(missingRecommendedFileNoticesCount).isEqualTo(1L); } private static List generateNotices( From 19a3143742fcd9f206450e19c256012581937ba4 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:15:02 -0400 Subject: [PATCH 15/43] missing import --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 9b6dd7a6d9..9f1c684eb0 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; import org.junit.Test; +import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedFileNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroups; From f5e6311a6c9d19601e7d60a87419aadefb5872ee Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:20:14 -0400 Subject: [PATCH 16/43] comparisonfailure --- .../gtfsvalidator/validator/MissingShapesFileValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index 5d1cbf3760..d1595cb434 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -43,7 +43,7 @@ public void validate(NoticeContainer noticeContainer) { Boolean missingShapes = shapeTable.isMissingFile(); Boolean hasLocationId = stopTimeTable.hasColumn("location_id"); Boolean hasLocationGroupId = stopTimeTable.hasColumn("location_group_id"); - Boolean hasLocationGroupsRecord = + Boolean hasLocationGroupsRecord = !locationGroupsTable.isMissingFile() && locationGroupsTable.entityCount() > 0; // Detect DRT usage from the data, not just from column presence. boolean hasLocationIdInData = false; From d5196e4ac4e04f96301ae46566b3072c43d4ba6b Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:33:03 -0400 Subject: [PATCH 17/43] we have to pass another arg, luckily its nullable --- .../validator/MissingShapesFileValidatorTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 9f1c684eb0..6f793304c2 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -14,6 +14,7 @@ import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; +import org.mobilitydata.gtfsvalidator.table.TableStatus; public class MissingShapesFileValidatorTest { @@ -60,6 +61,7 @@ public void testShapesFileAndFixedDrtPresent() { List notices = generateNotices( createShapeTable(1), + GtfsShapeTableContainer.forStatus(null), createStopTimesTable(1, "a", null), createLocationGroupsTable(1, "b", "testgroup")); boolean found = @@ -75,6 +77,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { List notices = generateNotices( createShapeTable(1), + GtfsShapeTableContainer.forStatus(null), createStopTimesTable(1, null, "c"), createLocationGroupsTable(1, "d", "t3stgroup")); boolean found = @@ -90,6 +93,7 @@ public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( createShapeTable(0), + GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE), createStopTimesTable(1, null, null), createLocationGroupsTable(0, null, null)); long missingRecommendedFileNoticesCount = @@ -103,6 +107,7 @@ public void testNoShapesFileAndNoDrtPresent() { private static List generateNotices( List shapes, + GtfsShapeTableContainer shapeContainer, List stopTimes, List locationGroups) { NoticeContainer noticeContainer = new NoticeContainer(); From 98c14d036c9b9ad740ad7e6e542f65fa9739334f Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:36:21 -0400 Subject: [PATCH 18/43] remove 1f check in favour of 1 --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 6f793304c2..7a26fd35d3 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -102,7 +102,7 @@ public void testNoShapesFileAndNoDrtPresent() { notice -> notice instanceof MissingRecommendedFileNotice) .count(); - assertThat(missingRecommendedFileNoticesCount).isEqualTo(1L); + assertThat(missingRecommendedFileNoticesCount).isEqualTo(1); } private static List generateNotices( From ce9c2247b6a482c56573f2e2447448dc45d7f50e Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:42:56 -0400 Subject: [PATCH 19/43] isAtLeast assertation check --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 7a26fd35d3..60be7f2b6b 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -102,7 +102,7 @@ public void testNoShapesFileAndNoDrtPresent() { notice -> notice instanceof MissingRecommendedFileNotice) .count(); - assertThat(missingRecommendedFileNoticesCount).isEqualTo(1); + assertThat(missingRecommendedFileNoticesCount).isAtLeast(1L);; } private static List generateNotices( From 244708883715b4d52c9b4cd5ddecce3a2cde66ef Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:48:06 -0400 Subject: [PATCH 20/43] not 1l? --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 60be7f2b6b..e6a0905416 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -102,7 +102,7 @@ public void testNoShapesFileAndNoDrtPresent() { notice -> notice instanceof MissingRecommendedFileNotice) .count(); - assertThat(missingRecommendedFileNoticesCount).isAtLeast(1L);; + assertThat(missingRecommendedFileNoticesCount).isAtLeast(1);; } private static List generateNotices( From 528b40914170d2711bc8f94d84ada61a969afac7 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:15:47 -0400 Subject: [PATCH 21/43] fix semicolon --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index e6a0905416..dd4f0d812b 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -102,7 +102,7 @@ public void testNoShapesFileAndNoDrtPresent() { notice -> notice instanceof MissingRecommendedFileNotice) .count(); - assertThat(missingRecommendedFileNoticesCount).isAtLeast(1);; + assertThat(missingRecommendedFileNoticesCount).isAtLeast(1); } private static List generateNotices( From dfe1600a9bf11b2a4a4687830aa9744585ed0f3d Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:05:46 -0400 Subject: [PATCH 22/43] correct tests and validator loop logic --- .../validator/MissingShapesFileValidator.java | 7 +++++-- .../validator/MissingShapesFileValidatorTest.java | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index d1595cb434..4b40c07e0a 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -41,6 +41,11 @@ public class MissingShapesFileValidator extends FileValidator { @Override public void validate(NoticeContainer noticeContainer) { Boolean missingShapes = shapeTable.isMissingFile(); + + if (!missingShapes) { + return; + } + Boolean hasLocationId = stopTimeTable.hasColumn("location_id"); Boolean hasLocationGroupId = stopTimeTable.hasColumn("location_group_id"); Boolean hasLocationGroupsRecord = @@ -64,12 +69,10 @@ public void validate(NoticeContainer noticeContainer) { // and also not have a record in location_groups.txt and not have a trip in stop_times.txt that // references location_group_id (required for Fixed-Stop DRT)? if (missingShapes && !hasLocationId && !hasLocationGroupsRecord && !hasLocationGroupId) { - for (GtfsStopTime stopTime : stopTimeTable.getEntities()) { noticeContainer.addValidationNotice( new MissingRecommendedFileNotice("shapes.txt")); // This is a feed-level warning; emit it at most once. break; - } } } } diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index dd4f0d812b..adcbcf231f 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -92,8 +92,6 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - createShapeTable(0), - GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE), createStopTimesTable(1, null, null), createLocationGroupsTable(0, null, null)); long missingRecommendedFileNoticesCount = From 22b978b2913518f85c834228ba1a8b1537584757 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:09:54 -0400 Subject: [PATCH 23/43] return, don't break --- .../gtfsvalidator/validator/MissingShapesFileValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index 4b40c07e0a..c35f323338 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -72,7 +72,7 @@ public void validate(NoticeContainer noticeContainer) { noticeContainer.addValidationNotice( new MissingRecommendedFileNotice("shapes.txt")); // This is a feed-level warning; emit it at most once. - break; + return; } } } From 69af53e7cbac99ee946b2fdfff495f5d78bf691c Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:20:09 -0400 Subject: [PATCH 24/43] lint --- .../validator/MissingShapesFileValidator.java | 17 ++++------------ .../MissingShapesFileValidatorTest.java | 20 ++++--------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index c35f323338..afc1dde086 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -1,20 +1,13 @@ package org.mobilitydata.gtfsvalidator.validator; -import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.WARNING; - import javax.inject.Inject; -import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice; -import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice.FileRefs; import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedFileNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; -import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeSchema; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsTripSchema; /** * Validates that the feed has either a `shapes.txt` file, or uses zone-based DRT or fixed-stops @@ -41,7 +34,6 @@ public class MissingShapesFileValidator extends FileValidator { @Override public void validate(NoticeContainer noticeContainer) { Boolean missingShapes = shapeTable.isMissingFile(); - if (!missingShapes) { return; } @@ -49,7 +41,7 @@ public void validate(NoticeContainer noticeContainer) { Boolean hasLocationId = stopTimeTable.hasColumn("location_id"); Boolean hasLocationGroupId = stopTimeTable.hasColumn("location_group_id"); Boolean hasLocationGroupsRecord = - !locationGroupsTable.isMissingFile() && locationGroupsTable.entityCount() > 0; + !locationGroupsTable.isMissingFile() && locationGroupsTable.entityCount() > 0; // Detect DRT usage from the data, not just from column presence. boolean hasLocationIdInData = false; boolean hasLocationGroupIdInData = false; @@ -69,10 +61,9 @@ public void validate(NoticeContainer noticeContainer) { // and also not have a record in location_groups.txt and not have a trip in stop_times.txt that // references location_group_id (required for Fixed-Stop DRT)? if (missingShapes && !hasLocationId && !hasLocationGroupsRecord && !hasLocationGroupId) { - noticeContainer.addValidationNotice( - new MissingRecommendedFileNotice("shapes.txt")); - // This is a feed-level warning; emit it at most once. - return; + noticeContainer.addValidationNotice(new MissingRecommendedFileNotice("shapes.txt")); + // This is a feed-level warning; emit it at most once. + return; } } } diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index adcbcf231f..3184ff472e 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -14,7 +14,6 @@ import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; -import org.mobilitydata.gtfsvalidator.table.TableStatus; public class MissingShapesFileValidatorTest { @@ -65,10 +64,7 @@ public void testShapesFileAndFixedDrtPresent() { createStopTimesTable(1, "a", null), createLocationGroupsTable(1, "b", "testgroup")); boolean found = - notices.stream() - .anyMatch( - notice -> - notice instanceof MissingRecommendedFileNotice); + notices.stream().anyMatch(notice -> notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); } @@ -81,10 +77,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { createStopTimesTable(1, null, "c"), createLocationGroupsTable(1, "d", "t3stgroup")); boolean found = - notices.stream() - .anyMatch( - notice -> - notice instanceof MissingRecommendedFileNotice); + notices.stream().anyMatch(notice -> notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); } @@ -92,14 +85,9 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - createStopTimesTable(1, null, null), - createLocationGroupsTable(0, null, null)); + createStopTimesTable(1, null, null), createLocationGroupsTable(0, null, null)); long missingRecommendedFileNoticesCount = - notices.stream() - .filter( - notice -> - notice instanceof MissingRecommendedFileNotice) - .count(); + notices.stream().filter(notice -> notice instanceof MissingRecommendedFileNotice).count(); assertThat(missingRecommendedFileNoticesCount).isAtLeast(1); } From 04c063881e694ca9d5e7cbe2611bc6f448f6c80d Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:25:00 -0400 Subject: [PATCH 25/43] fully remove arguments --- .../validator/MissingShapesFileValidatorTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 3184ff472e..c63a034f64 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -60,7 +60,6 @@ public void testShapesFileAndFixedDrtPresent() { List notices = generateNotices( createShapeTable(1), - GtfsShapeTableContainer.forStatus(null), createStopTimesTable(1, "a", null), createLocationGroupsTable(1, "b", "testgroup")); boolean found = @@ -73,7 +72,6 @@ public void testShapesFileAndZoneBasedDrtPresent() { List notices = generateNotices( createShapeTable(1), - GtfsShapeTableContainer.forStatus(null), createStopTimesTable(1, null, "c"), createLocationGroupsTable(1, "d", "t3stgroup")); boolean found = @@ -85,7 +83,9 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - createStopTimesTable(1, null, null), createLocationGroupsTable(0, null, null)); + createShapeTable(null), + createStopTimesTable(1, null, null), + createLocationGroupsTable(0, null, null)); long missingRecommendedFileNoticesCount = notices.stream().filter(notice -> notice instanceof MissingRecommendedFileNotice).count(); assertThat(missingRecommendedFileNoticesCount).isAtLeast(1); @@ -93,7 +93,6 @@ public void testNoShapesFileAndNoDrtPresent() { private static List generateNotices( List shapes, - GtfsShapeTableContainer shapeContainer, List stopTimes, List locationGroups) { NoticeContainer noticeContainer = new NoticeContainer(); From 3763437da296e5823b06f5e9e38d60cf02b5d1ed Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:27:34 -0400 Subject: [PATCH 26/43] 0 rows --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index c63a034f64..01f2f0da41 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -83,7 +83,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - createShapeTable(null), + createShapeTable(0), createStopTimesTable(1, null, null), createLocationGroupsTable(0, null, null)); long missingRecommendedFileNoticesCount = From 6962ced2208f1db81ee32e95f6b4adfaf9e3bcaa Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:32:27 -0400 Subject: [PATCH 27/43] -1 rows --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 01f2f0da41..dc512f7b45 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -83,7 +83,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - createShapeTable(0), + createShapeTable(-1), createStopTimesTable(1, null, null), createLocationGroupsTable(0, null, null)); long missingRecommendedFileNoticesCount = From 516dab913b1688b97c82c35f3137dafcaef95a91 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:37:43 -0400 Subject: [PATCH 28/43] break if rows are -1 --- .../validator/MissingShapesFileValidatorTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index dc512f7b45..78000d20d0 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -20,6 +20,9 @@ public class MissingShapesFileValidatorTest { private static List createShapeTable(int rows) { ArrayList shapes = new ArrayList<>(); for (int i = 0; i < rows; i++) { + if (rows == -1) { + break; + } shapes.add(new GtfsShape.Builder().setCsvRowNumber(i + 1).setShapeId("s" + i).build()); } return shapes; From b86fa31f2e7e0f741f9b36fe544d7e6725b70d3c Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 16:41:12 -0400 Subject: [PATCH 29/43] try returning --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 78000d20d0..c478a2d259 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -21,7 +21,7 @@ private static List createShapeTable(int rows) { ArrayList shapes = new ArrayList<>(); for (int i = 0; i < rows; i++) { if (rows == -1) { - break; + return null; } shapes.add(new GtfsShape.Builder().setCsvRowNumber(i + 1).setShapeId("s" + i).build()); } From d7de502982e7c8479cc1c03ef6c2de13536aa087 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 4 May 2026 19:47:02 -0400 Subject: [PATCH 30/43] [Skip CI] push method signature WIP --- .../reportsummary/model/FeedMetadata.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java index 26f102215a..49b01db7f2 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java @@ -183,8 +183,8 @@ private int loadUniqueCount( * "Zone-Based Demand Responsive Transit" feature. * @return true if at least one trip with only location_id is found, false otherwise. */ - private boolean hasAtLeastOneTripWithOnlyLocationId(GtfsFeedContainer feedContainer) { - var optionalStopTimeTable = feedContainer.getTableForFilename(GtfsStopTime.FILENAME); + public static boolean hasAtLeastOneTripWithOnlyLocationId(E extendedTable, FeedContainer feedContainer) { + var optionalStopTimeTable = extendedTable.getTableForFilename(GtfsStopTime.FILENAME); if (optionalStopTimeTable.isPresent()) { for (GtfsEntity entity : optionalStopTimeTable.get().getEntities()) { if (entity instanceof GtfsStopTime) { @@ -206,8 +206,8 @@ private boolean hasAtLeastOneTripWithOnlyLocationId(GtfsFeedContainer feedContai * "Fixed-Stops Demand Responsive Transit" feature. * @return true if at least one trip with only location_group_id is found, false otherwise. */ - private boolean hasAtLeastOneTripWithOnlyLocationGroupId(GtfsFeedContainer feedContainer) { - var optionalStopTimeTable = feedContainer.getTableForFilename(GtfsStopTime.FILENAME); + public static boolean hasAtLeastOneTripWithOnlyLocationGroupId(E extendedTable, GtfsFeedContainer feedContainer) { + var optionalStopTimeTable = extendedTable.getTableForFilename(GtfsStopTime.FILENAME); if (optionalStopTimeTable.isPresent()) { for (GtfsEntity entity : optionalStopTimeTable.get().getEntities()) { if (entity instanceof GtfsStopTime) { @@ -791,9 +791,9 @@ public void loadServiceWindow( } } - private boolean hasAtLeastOneRecordInFile( - GtfsFeedContainer feedContainer, String featureFilename) { - var table = feedContainer.getTableForFilename(featureFilename); + public static boolean hasAtLeastOneRecordInFile( + E extendedTable, GtfsFeedContainer feedContainer, String featureFilename) { + var table = extendedTable.getTableForFilename(featureFilename); return table.isPresent() && table.get().entityCount() > 0; } From e4e72a856aa3613070ba176e71ee2c1f49c1e70b Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 3 Jun 2026 11:38:03 -0400 Subject: [PATCH 31/43] rely on FeedMetadata in validator method --- .../reportsummary/model/FeedMetadata.java | 14 +++--- .../validator/MissingShapesFileValidator.java | 50 ++++++------------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java index 49b01db7f2..e6c7db5ecf 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/reportsummary/model/FeedMetadata.java @@ -183,8 +183,8 @@ private int loadUniqueCount( * "Zone-Based Demand Responsive Transit" feature. * @return true if at least one trip with only location_id is found, false otherwise. */ - public static boolean hasAtLeastOneTripWithOnlyLocationId(E extendedTable, FeedContainer feedContainer) { - var optionalStopTimeTable = extendedTable.getTableForFilename(GtfsStopTime.FILENAME); + public static boolean hasAtLeastOneTripWithOnlyLocationId(GtfsFeedContainer feedContainer) { + var optionalStopTimeTable = feedContainer.getTableForFilename(GtfsStopTime.FILENAME); if (optionalStopTimeTable.isPresent()) { for (GtfsEntity entity : optionalStopTimeTable.get().getEntities()) { if (entity instanceof GtfsStopTime) { @@ -206,8 +206,8 @@ public static boolean hasAtLeastOneTripWithOnlyL * "Fixed-Stops Demand Responsive Transit" feature. * @return true if at least one trip with only location_group_id is found, false otherwise. */ - public static boolean hasAtLeastOneTripWithOnlyLocationGroupId(E extendedTable, GtfsFeedContainer feedContainer) { - var optionalStopTimeTable = extendedTable.getTableForFilename(GtfsStopTime.FILENAME); + public static boolean hasAtLeastOneTripWithOnlyLocationGroupId(GtfsFeedContainer feedContainer) { + var optionalStopTimeTable = feedContainer.getTableForFilename(GtfsStopTime.FILENAME); if (optionalStopTimeTable.isPresent()) { for (GtfsEntity entity : optionalStopTimeTable.get().getEntities()) { if (entity instanceof GtfsStopTime) { @@ -791,9 +791,9 @@ public void loadServiceWindow( } } - public static boolean hasAtLeastOneRecordInFile( - E extendedTable, GtfsFeedContainer feedContainer, String featureFilename) { - var table = extendedTable.getTableForFilename(featureFilename); + public static boolean hasAtLeastOneRecordInFile( + GtfsFeedContainer feedContainer, String featureFilename) { + var table = feedContainer.getTableForFilename(featureFilename); return table.isPresent() && table.get().entityCount() > 0; } diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index afc1dde086..6aa67e53aa 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -4,10 +4,10 @@ import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator; import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedFileNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; +import org.mobilitydata.gtfsvalidator.reportsummary.model.FeedMetadata; +import org.mobilitydata.gtfsvalidator.table.GtfsFeedContainer; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; /** * Validates that the feed has either a `shapes.txt` file, or uses zone-based DRT or fixed-stops @@ -18,49 +18,31 @@ @GtfsValidator public class MissingShapesFileValidator extends FileValidator { private final GtfsShapeTableContainer shapeTable; - private final GtfsStopTimeTableContainer stopTimeTable; - private final GtfsLocationGroupsTableContainer locationGroupsTable; + private final GtfsLocationGroupsTableContainer locationGroups; + private final GtfsFeedContainer feedContainer; @Inject MissingShapesFileValidator( GtfsShapeTableContainer shapeTable, - GtfsStopTimeTableContainer stopTimeTable, - GtfsLocationGroupsTableContainer locationGroupsTable) { + GtfsLocationGroupsTableContainer locationGroups, + GtfsFeedContainer feedContainer) { this.shapeTable = shapeTable; - this.stopTimeTable = stopTimeTable; - this.locationGroupsTable = locationGroupsTable; + this.locationGroups = locationGroups; + this.feedContainer = feedContainer; } @Override public void validate(NoticeContainer noticeContainer) { - Boolean missingShapes = shapeTable.isMissingFile(); - if (!missingShapes) { - return; - } - Boolean hasLocationId = stopTimeTable.hasColumn("location_id"); - Boolean hasLocationGroupId = stopTimeTable.hasColumn("location_group_id"); - Boolean hasLocationGroupsRecord = - !locationGroupsTable.isMissingFile() && locationGroupsTable.entityCount() > 0; - // Detect DRT usage from the data, not just from column presence. - boolean hasLocationIdInData = false; - boolean hasLocationGroupIdInData = false; - for (GtfsStopTime stopTime : stopTimeTable.getEntities()) { - if (stopTime.hasLocationId()) { - hasLocationIdInData = true; - } - if (stopTime.hasLocationGroupId()) { - hasLocationGroupIdInData = true; - } - if (hasLocationIdInData && hasLocationGroupIdInData) { - break; - } - } + Boolean missingShapes = shapeTable == null || shapeTable.isMissingFile(); + boolean hasZoneBasedDrt = FeedMetadata.hasAtLeastOneTripWithOnlyLocationId(feedContainer); + boolean hasFixedStopsDrt = + FeedMetadata.hasAtLeastOneRecordInFile(feedContainer, locationGroups.FILENAME) + && FeedMetadata.hasAtLeastOneTripWithOnlyLocationGroupId(feedContainer); - // Do we not have: a shapes.txt file and not have a location_id (required for Zone-Based DRT), - // and also not have a record in location_groups.txt and not have a trip in stop_times.txt that - // references location_group_id (required for Fixed-Stop DRT)? - if (missingShapes && !hasLocationId && !hasLocationGroupsRecord && !hasLocationGroupId) { + // Do we NOT have: a shapes.txt file and the required fields for Zone-Based DRT, + // and also the required fields for Fixed-Stop DRT? + if (missingShapes && !hasZoneBasedDrt && !hasFixedStopsDrt) { noticeContainer.addValidationNotice(new MissingRecommendedFileNotice("shapes.txt")); // This is a feed-level warning; emit it at most once. return; From 7d7564dc997cf1cb5da3caf8242478302bc2197d Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 3 Jun 2026 11:41:03 -0400 Subject: [PATCH 32/43] stringify filename --- .../gtfsvalidator/validator/MissingShapesFileValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java index 6aa67e53aa..39d9f35389 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidator.java @@ -37,7 +37,7 @@ public void validate(NoticeContainer noticeContainer) { Boolean missingShapes = shapeTable == null || shapeTable.isMissingFile(); boolean hasZoneBasedDrt = FeedMetadata.hasAtLeastOneTripWithOnlyLocationId(feedContainer); boolean hasFixedStopsDrt = - FeedMetadata.hasAtLeastOneRecordInFile(feedContainer, locationGroups.FILENAME) + FeedMetadata.hasAtLeastOneRecordInFile(feedContainer, "location_groups.txt") && FeedMetadata.hasAtLeastOneTripWithOnlyLocationGroupId(feedContainer); // Do we NOT have: a shapes.txt file and the required fields for Zone-Based DRT, From 86e77efd4e91d176860b0a665209943a9115d3e6 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 3 Jun 2026 11:52:55 -0400 Subject: [PATCH 33/43] pass single feedContainer --- .../validator/MissingShapesFileValidatorTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index c478a2d259..c825c263c4 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -14,6 +14,7 @@ import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; +import org.mobilitydata.gtfsvalidator.table.GtfsFeedContainer; public class MissingShapesFileValidatorTest { @@ -96,13 +97,13 @@ public void testNoShapesFileAndNoDrtPresent() { private static List generateNotices( List shapes, - List stopTimes, - List locationGroups) { + List locationGroups, + GtfsFeedContainer feedContainer) { NoticeContainer noticeContainer = new NoticeContainer(); new MissingShapesFileValidator( GtfsShapeTableContainer.forEntities(shapes, noticeContainer), - GtfsStopTimeTableContainer.forEntities(stopTimes, noticeContainer), - GtfsLocationGroupsTableContainer.forEntities(locationGroups, noticeContainer)) + GtfsLocationGroupsTableContainer.forEntities(locationGroups, noticeContainer), + feedContainer) .validate(noticeContainer); return noticeContainer.getValidationNotices(); } From ccaedfda028c07e6e50b3c6abdb4d933b87f198f Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 3 Jun 2026 11:55:06 -0400 Subject: [PATCH 34/43] lint --- .../validator/MissingShapesFileValidatorTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index c825c263c4..41f6f16bcd 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -8,13 +8,12 @@ import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedFileNotice; import org.mobilitydata.gtfsvalidator.notice.NoticeContainer; import org.mobilitydata.gtfsvalidator.notice.ValidationNotice; +import org.mobilitydata.gtfsvalidator.table.GtfsFeedContainer; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroups; import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsFeedContainer; public class MissingShapesFileValidatorTest { From 52b330e641ba803957cca1f89d824ecca5e9b84e Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:09:03 -0400 Subject: [PATCH 35/43] add createFeedContainer() --- .../MissingShapesFileValidatorTest.java | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 41f6f16bcd..22280a3762 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -3,6 +3,7 @@ import static com.google.common.truth.Truth.assertThat; import java.util.ArrayList; +import com.google.common.collect.ImmutableList; import java.util.List; import org.junit.Test; import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedFileNotice; @@ -13,10 +14,20 @@ import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; -import org.mobilitydata.gtfsvalidator.table.GtfsStopTime; + public class MissingShapesFileValidatorTest { + private static GtfsFeedContainer createFeedContainer( + List shapes, + List locationGroups) { + NoticeContainer noticeContainer = new NoticeContainer(); + return new GtfsFeedContainer( + ImmutableList.of( + GtfsShapeTableContainer.forEntities(shapes, noticeContainer), + GtfsLocationGroupsTableContainer.forEntities(locationGroups, noticeContainer))); +} + private static List createShapeTable(int rows) { ArrayList shapes = new ArrayList<>(); for (int i = 0; i < rows; i++) { @@ -28,22 +39,6 @@ private static List createShapeTable(int rows) { return shapes; } - private static List createStopTimesTable( - int rows, String locationGroupId, String locationId) { - ArrayList stopTimes = new ArrayList<>(); - for (int i = 0; i < rows; i++) { - stopTimes.add( - new GtfsStopTime.Builder() - .setCsvRowNumber(i + 1) - .setLocationGroupId(locationGroupId) - .setLocationId(locationId) - .setTripId(locationGroupId) - .setStopSequence(i + 1) - .build()); - } - return stopTimes; - } - private static List createLocationGroupsTable( int rows, String groupId, String groupName) { ArrayList locationGroups = new ArrayList<>(); @@ -63,8 +58,8 @@ public void testShapesFileAndFixedDrtPresent() { List notices = generateNotices( createShapeTable(1), - createStopTimesTable(1, "a", null), - createLocationGroupsTable(1, "b", "testgroup")); + createLocationGroupsTable(1, "b", "testgroup"), + createFeedContainer(createShapeTable(1), createLocationGroupsTable(1, "b", "testgroup"))); boolean found = notices.stream().anyMatch(notice -> notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); @@ -75,8 +70,8 @@ public void testShapesFileAndZoneBasedDrtPresent() { List notices = generateNotices( createShapeTable(1), - createStopTimesTable(1, null, "c"), - createLocationGroupsTable(1, "d", "t3stgroup")); + createLocationGroupsTable(1, "d", "t3stgroup"), + createFeedContainer(createShapeTable(1), createLocationGroupsTable(1, "d", "t3stgroup"))); boolean found = notices.stream().anyMatch(notice -> notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); @@ -87,8 +82,8 @@ public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( createShapeTable(-1), - createStopTimesTable(1, null, null), - createLocationGroupsTable(0, null, null)); + createLocationGroupsTable(0, null, null), + createFeedContainer(createShapeTable(-1), createLocationGroupsTable(0, null, null))); long missingRecommendedFileNoticesCount = notices.stream().filter(notice -> notice instanceof MissingRecommendedFileNotice).count(); assertThat(missingRecommendedFileNoticesCount).isAtLeast(1); From 049e820ab939d3204c6c8988549b16ebecb648b4 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:11:19 -0400 Subject: [PATCH 36/43] lint --- .../MissingShapesFileValidatorTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 22280a3762..f6b8477bae 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -2,8 +2,8 @@ import static com.google.common.truth.Truth.assertThat; -import java.util.ArrayList; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.mobilitydata.gtfsvalidator.notice.MissingRecommendedFileNotice; @@ -15,18 +15,16 @@ import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; - public class MissingShapesFileValidatorTest { private static GtfsFeedContainer createFeedContainer( - List shapes, - List locationGroups) { - NoticeContainer noticeContainer = new NoticeContainer(); - return new GtfsFeedContainer( - ImmutableList.of( - GtfsShapeTableContainer.forEntities(shapes, noticeContainer), - GtfsLocationGroupsTableContainer.forEntities(locationGroups, noticeContainer))); -} + List shapes, List locationGroups) { + NoticeContainer noticeContainer = new NoticeContainer(); + return new GtfsFeedContainer( + ImmutableList.of( + GtfsShapeTableContainer.forEntities(shapes, noticeContainer), + GtfsLocationGroupsTableContainer.forEntities(locationGroups, noticeContainer))); + } private static List createShapeTable(int rows) { ArrayList shapes = new ArrayList<>(); @@ -59,7 +57,8 @@ public void testShapesFileAndFixedDrtPresent() { generateNotices( createShapeTable(1), createLocationGroupsTable(1, "b", "testgroup"), - createFeedContainer(createShapeTable(1), createLocationGroupsTable(1, "b", "testgroup"))); + createFeedContainer( + createShapeTable(1), createLocationGroupsTable(1, "b", "testgroup"))); boolean found = notices.stream().anyMatch(notice -> notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); @@ -71,7 +70,8 @@ public void testShapesFileAndZoneBasedDrtPresent() { generateNotices( createShapeTable(1), createLocationGroupsTable(1, "d", "t3stgroup"), - createFeedContainer(createShapeTable(1), createLocationGroupsTable(1, "d", "t3stgroup"))); + createFeedContainer( + createShapeTable(1), createLocationGroupsTable(1, "d", "t3stgroup"))); boolean found = notices.stream().anyMatch(notice -> notice instanceof MissingRecommendedFileNotice); assertThat(found).isFalse(); From d3ba6fd5779ec34c8e9fc8f51484fdd09379bcc6 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:53:10 -0400 Subject: [PATCH 37/43] Update main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java Co-authored-by: David Gamez <1192523+davidgamez@users.noreply.github.com> --- .../validator/MissingShapesFileValidatorTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index f6b8477bae..078b3ef53a 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -29,9 +29,6 @@ private static GtfsFeedContainer createFeedContainer( private static List createShapeTable(int rows) { ArrayList shapes = new ArrayList<>(); for (int i = 0; i < rows; i++) { - if (rows == -1) { - return null; - } shapes.add(new GtfsShape.Builder().setCsvRowNumber(i + 1).setShapeId("s" + i).build()); } return shapes; From da570f47e204a25a3912a7f3f7574b5bdd8db4c2 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:55:04 -0400 Subject: [PATCH 38/43] forStatus --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 078b3ef53a..7f43ac94fe 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -78,7 +78,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - createShapeTable(-1), + GtfsShapeTableContainer shapeTable = GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE);, createLocationGroupsTable(0, null, null), createFeedContainer(createShapeTable(-1), createLocationGroupsTable(0, null, null))); long missingRecommendedFileNoticesCount = From e1c419d0bc39c53dbc4007208754ed4505462c39 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 15 Jun 2026 16:02:45 -0400 Subject: [PATCH 39/43] remove semicolon --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 7f43ac94fe..9b2892dc85 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -78,7 +78,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - GtfsShapeTableContainer shapeTable = GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE);, + GtfsShapeTableContainer shapeTable = GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE), createLocationGroupsTable(0, null, null), createFeedContainer(createShapeTable(-1), createLocationGroupsTable(0, null, null))); long missingRecommendedFileNoticesCount = From 41e6fb2e381a49d7e8c988dece18b43882f46530 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 15 Jun 2026 16:04:06 -0400 Subject: [PATCH 40/43] change to createShapeTable --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 9b2892dc85..87e38574b8 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -78,7 +78,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - GtfsShapeTableContainer shapeTable = GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE), + createShapeTable.forStatus(TableStatus.MISSING_FILE), createLocationGroupsTable(0, null, null), createFeedContainer(createShapeTable(-1), createLocationGroupsTable(0, null, null))); long missingRecommendedFileNoticesCount = From 390eb9e9638e212c6c296669189aa660419b8fe0 Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Mon, 15 Jun 2026 16:08:01 -0400 Subject: [PATCH 41/43] not a forStatus? --- .../gtfsvalidator/validator/MissingShapesFileValidatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 87e38574b8..05a5753052 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -78,7 +78,7 @@ public void testShapesFileAndZoneBasedDrtPresent() { public void testNoShapesFileAndNoDrtPresent() { List notices = generateNotices( - createShapeTable.forStatus(TableStatus.MISSING_FILE), + createShapeTable(TableStatus.MISSING_FILE), createLocationGroupsTable(0, null, null), createFeedContainer(createShapeTable(-1), createLocationGroupsTable(0, null, null))); long missingRecommendedFileNoticesCount = From de8c979a472953fe67e7a9fa380c75b7043e5b7a Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 19 Jun 2026 22:29:35 -0400 Subject: [PATCH 42/43] guided copilot feedContainer() logic change --- .../MissingShapesFileValidatorTest.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 05a5753052..7a0c3f852e 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -14,6 +14,7 @@ import org.mobilitydata.gtfsvalidator.table.GtfsLocationGroupsTableContainer; import org.mobilitydata.gtfsvalidator.table.GtfsShape; import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer; +import org.mobilitydata.gtfsvalidator.table.TableStatus; public class MissingShapesFileValidatorTest { @@ -76,16 +77,33 @@ public void testShapesFileAndZoneBasedDrtPresent() { @Test public void testNoShapesFileAndNoDrtPresent() { + // Create containers where shapes.txt is missing and location_groups is empty + var shapeContainer = GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE); + var locationGroupsContainer = + GtfsLocationGroupsTableContainer.forEntities(createLocationGroupsTable(0, null, null), new NoticeContainer()); + GtfsFeedContainer feedContainer = createFeedContainer(shapeContainer, locationGroupsContainer); + List notices = - generateNotices( - createShapeTable(TableStatus.MISSING_FILE), - createLocationGroupsTable(0, null, null), - createFeedContainer(createShapeTable(-1), createLocationGroupsTable(0, null, null))); + generateNotices(shapeContainer, locationGroupsContainer, feedContainer); long missingRecommendedFileNoticesCount = notices.stream().filter(notice -> notice instanceof MissingRecommendedFileNotice).count(); assertThat(missingRecommendedFileNoticesCount).isAtLeast(1); } + private static GtfsFeedContainer createFeedContainer( + GtfsShapeTableContainer shapeContainer, GtfsLocationGroupsTableContainer locationGroupsContainer) { + return new GtfsFeedContainer(ImmutableList.of(shapeContainer, locationGroupsContainer)); + } + + private static List generateNotices( + GtfsShapeTableContainer shapeTable, + GtfsLocationGroupsTableContainer locationGroups, + GtfsFeedContainer feedContainer) { + NoticeContainer noticeContainer = new NoticeContainer(); + new MissingShapesFileValidator(shapeTable, locationGroups, feedContainer).validate(noticeContainer); + return noticeContainer.getValidationNotices(); + } + private static List generateNotices( List shapes, List locationGroups, From f8aff1214dd2fce8270509c8cfa07082edcd92aa Mon Sep 17 00:00:00 2001 From: Charlotte Wilson <251223230+cswilson252@users.noreply.github.com> Date: Fri, 19 Jun 2026 22:31:45 -0400 Subject: [PATCH 43/43] lint --- .../validator/MissingShapesFileValidatorTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java index 7a0c3f852e..20285a205e 100644 --- a/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java +++ b/main/src/test/java/org/mobilitydata/gtfsvalidator/validator/MissingShapesFileValidatorTest.java @@ -80,7 +80,8 @@ public void testNoShapesFileAndNoDrtPresent() { // Create containers where shapes.txt is missing and location_groups is empty var shapeContainer = GtfsShapeTableContainer.forStatus(TableStatus.MISSING_FILE); var locationGroupsContainer = - GtfsLocationGroupsTableContainer.forEntities(createLocationGroupsTable(0, null, null), new NoticeContainer()); + GtfsLocationGroupsTableContainer.forEntities( + createLocationGroupsTable(0, null, null), new NoticeContainer()); GtfsFeedContainer feedContainer = createFeedContainer(shapeContainer, locationGroupsContainer); List notices = @@ -91,7 +92,8 @@ public void testNoShapesFileAndNoDrtPresent() { } private static GtfsFeedContainer createFeedContainer( - GtfsShapeTableContainer shapeContainer, GtfsLocationGroupsTableContainer locationGroupsContainer) { + GtfsShapeTableContainer shapeContainer, + GtfsLocationGroupsTableContainer locationGroupsContainer) { return new GtfsFeedContainer(ImmutableList.of(shapeContainer, locationGroupsContainer)); } @@ -100,7 +102,8 @@ private static List generateNotices( GtfsLocationGroupsTableContainer locationGroups, GtfsFeedContainer feedContainer) { NoticeContainer noticeContainer = new NoticeContainer(); - new MissingShapesFileValidator(shapeTable, locationGroups, feedContainer).validate(noticeContainer); + new MissingShapesFileValidator(shapeTable, locationGroups, feedContainer) + .validate(noticeContainer); return noticeContainer.getValidationNotices(); }