Skip to content

Commit

Permalink
feat: stop_times.txt and locations.geojson foreign key validation (#1951
Browse files Browse the repository at this point in the history
)
  • Loading branch information
cka-y authored Jan 28, 2025
1 parent e9258a2 commit bfc5ef0
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.mobilitydata.gtfsvalidator.validator;

import javax.inject.Inject;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
import org.mobilitydata.gtfsvalidator.notice.ForeignKeyViolationNotice;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.table.GtfsGeoJsonFeature;
import org.mobilitydata.gtfsvalidator.table.GtfsGeoJsonFeaturesContainer;
import org.mobilitydata.gtfsvalidator.table.GtfsStopTime;
import org.mobilitydata.gtfsvalidator.table.GtfsStopTimeTableContainer;

@GtfsValidator
public class LocationIdForeignKeyValidator extends FileValidator {
private final GtfsGeoJsonFeaturesContainer locationGeoJSONTable;
private final GtfsStopTimeTableContainer stopTimeTable;

@Inject
public LocationIdForeignKeyValidator(
GtfsGeoJsonFeaturesContainer locationGeoJSONTable, GtfsStopTimeTableContainer stopTimeTable) {
this.locationGeoJSONTable = locationGeoJSONTable;
this.stopTimeTable = stopTimeTable;
}

@Override
public boolean shouldCallValidate() {
// The location_id column is optional, so we should only call validate if the column exists.
return stopTimeTable != null
&& locationGeoJSONTable != null
&& stopTimeTable.hasColumn(GtfsStopTime.LOCATION_ID_FIELD_NAME);
}

@Override
public void validate(NoticeContainer noticeContainer) {
for (GtfsStopTime stopTime : stopTimeTable.getEntities()) {
String foreignKey = stopTime.locationId();
if (foreignKey.isEmpty()) {
continue;
}
if (!locationGeoJSONTable.byLocationIdMap().containsKey(foreignKey)) {
noticeContainer.addValidationNotice(
new ForeignKeyViolationNotice(
GtfsStopTime.FILENAME,
GtfsStopTime.LOCATION_ID_FIELD_NAME,
GtfsGeoJsonFeature.FILENAME,
GtfsGeoJsonFeature.FEATURE_ID_FIELD_NAME,
foreignKey,
stopTime.csvRowNumber()));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.mobilitydata.gtfsvalidator.validator;

import static com.google.common.truth.Truth.assertThat;

import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.function.Consumer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mobilitydata.gtfsvalidator.notice.ForeignKeyViolationNotice;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.table.*;

@RunWith(JUnit4.class)
public class LocationIdForeignKeyValidatorTest {
private static <T> T configure(T obj, Consumer<T> configurator) {
configurator.accept(obj);
return obj;
}

@Test
public void missingGeoJSONId_yieldsNotice() {
NoticeContainer noticeContainer = new NoticeContainer();
GtfsGeoJsonFileDescriptor descriptor = new GtfsGeoJsonFileDescriptor();
List<GtfsGeoJsonFeature> geoJsonFeatures =
ImmutableList.of(
configure(
new GtfsGeoJsonFeature(),
f -> {
f.setFeatureId("locationId");
}));
GtfsGeoJsonFeaturesContainer geoJsonFeaturesContainer =
descriptor.createContainerForEntities(geoJsonFeatures, noticeContainer);
List<GtfsStopTime> stopTimes =
ImmutableList.of(
new GtfsStopTime.Builder().setCsvRowNumber(1).setLocationId("locationId2").build());
GtfsStopTimeTableContainer stopTimeTableContainer =
GtfsStopTimeTableContainer.forEntities(stopTimes, noticeContainer);
new LocationIdForeignKeyValidator(geoJsonFeaturesContainer, stopTimeTableContainer)
.validate(noticeContainer);
assertThat(noticeContainer.getValidationNotices())
.containsExactly(
new ForeignKeyViolationNotice(
"stop_times.txt", "location_id", "locations.geojson", "id", "locationId2", 1));
}

@Test
public void existingGeoJSONId_yieldsNoNotice() {
NoticeContainer noticeContainer = new NoticeContainer();
GtfsGeoJsonFileDescriptor descriptor = new GtfsGeoJsonFileDescriptor();
List<GtfsGeoJsonFeature> geoJsonFeatures =
ImmutableList.of(
configure(
new GtfsGeoJsonFeature(),
f -> {
f.setFeatureId("locationId");
}));
GtfsGeoJsonFeaturesContainer geoJsonFeaturesContainer =
descriptor.createContainerForEntities(geoJsonFeatures, noticeContainer);
List<GtfsStopTime> stopTimes =
ImmutableList.of(
new GtfsStopTime.Builder().setCsvRowNumber(1).setLocationId("locationId").build());
GtfsStopTimeTableContainer stopTimeTableContainer =
GtfsStopTimeTableContainer.forEntities(stopTimes, noticeContainer);
new LocationIdForeignKeyValidator(geoJsonFeaturesContainer, stopTimeTableContainer)
.validate(noticeContainer);
assertThat(noticeContainer.getValidationNotices()).isEmpty();
}
}

0 comments on commit bfc5ef0

Please sign in to comment.