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();
}