Skip to content

Commit

Permalink
Merge 9cd9991 into c79ea99
Browse files Browse the repository at this point in the history
  • Loading branch information
cka-y authored Feb 27, 2024
2 parents c79ea99 + 9cd9991 commit 6f69f45
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.mobilitydata.gtfsvalidator.table;

import org.mobilitydata.gtfsvalidator.annotation.*;

@GtfsTable("route_networks.txt")
public interface GtfsRouteNetworkSchema extends GtfsEntity {
@FieldType(FieldTypeEnum.ID)
@ForeignKey(table = "routes.txt", field = "route_id")
@Required
@PrimaryKey
String routeId();

@FieldType(FieldTypeEnum.ID)
@ForeignKey(table = "networks.txt", field = "network_id")
@Required
String networkId();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.mobilitydata.gtfsvalidator.validator;

import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.ERROR;

import javax.inject.Inject;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
import org.mobilitydata.gtfsvalidator.table.*;

@GtfsValidator
public class NetworkIdConsistencyValidator extends FileValidator {
private final GtfsRouteTableContainer routeTableContainer;
private final GtfsRouteNetworkTableContainer routeNetworkTableContainer;

private final GtfsNetworkTableContainer networkTableContainer;

@Inject
NetworkIdConsistencyValidator(
GtfsRouteTableContainer routes,
GtfsRouteNetworkTableContainer routeNetworks,
GtfsNetworkTableContainer networks) {
this.routeTableContainer = routes;
this.routeNetworkTableContainer = routeNetworks;
this.networkTableContainer = networks;
}

@Override
public void validate(NoticeContainer noticeContainer) {
// Validate the presence of network_id in routes and its specification in either route_network
// or network files
boolean hasNetworkIdField = this.routeTableContainer.hasColumn(GtfsRoute.NETWORK_ID_FIELD_NAME);
if (hasNetworkIdField) {
if (!this.routeNetworkTableContainer.isMissingFile()) {
noticeContainer.addValidationNotice(
new RouteNetworksSpecifiedInMoreThanOneFileNotice(
GtfsRoute.FILENAME, GtfsRouteNetwork.FILENAME, GtfsRoute.NETWORK_ID_FIELD_NAME));
}
if (!this.networkTableContainer.isMissingFile()) {
noticeContainer.addValidationNotice(
new RouteNetworksSpecifiedInMoreThanOneFileNotice(
GtfsRoute.FILENAME, GtfsNetwork.FILENAME, GtfsRoute.NETWORK_ID_FIELD_NAME));
}
}
}

/**
* Indicates that route network identifiers are specified across multiple files.
*
* <p>This notice highlights a data integrity issue where route network specifications are
* redundantly defined in more than one file. According to specifications, a route network
* identifier should be uniquely defined in a single file. Any additional definitions of route
* network specifications in other files are considered conditionally forbidden.
*/
@GtfsValidationNotice(
severity = ERROR,
files =
@GtfsValidationNotice.FileRefs({
GtfsRouteSchema.class,
GtfsRouteNetworkSchema.class,
GtfsNetworkSchema.class
}))
static class RouteNetworksSpecifiedInMoreThanOneFileNotice extends ValidationNotice {
/** Name of the field in fileNameA */
private final String fieldName;

/** The name of the first file. */
private final String fileNameA;

/** The name of the second file which presence duplicates route networks specification. */
private final String fileNameB;

RouteNetworksSpecifiedInMoreThanOneFileNotice(
String filename1, String filename2, String fieldName) {
this.fileNameA = filename1;
this.fileNameB = filename2;
this.fieldName = fieldName;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.mobilitydata.gtfsvalidator.validator;

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

import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.parsing.CsvHeader;
import org.mobilitydata.gtfsvalidator.table.*;

public class NetworkIdConsistencyValidatorTest {

private NoticeContainer noticeContainer;
private GtfsRouteTableContainer routeTableContainer;
private GtfsRouteNetworkTableContainer routeNetworkTableContainer;
private GtfsNetworkTableContainer networkTableContainer;

@Before
public void setup() {
noticeContainer = new NoticeContainer();
routeTableContainer =
GtfsRouteTableContainer.forHeaderAndEntities(
new GtfsRouteTableDescriptor(),
new CsvHeader(ImmutableList.of("route_id", "network_id").toArray(new String[0])),
ImmutableList.of(
new GtfsRoute.Builder().setRouteId("123").setNetworkId("network1").build()),
noticeContainer);
routeNetworkTableContainer =
new GtfsRouteNetworkTableContainer(
new GtfsRouteNetworkTableDescriptor(), GtfsTableContainer.TableStatus.MISSING_FILE);
networkTableContainer =
new GtfsNetworkTableContainer(
new GtfsNetworkTableDescriptor(), GtfsTableContainer.TableStatus.MISSING_FILE);
}

@Test
public void validatesConditionalForbiddenFilePresenceNoNotice() {
NetworkIdConsistencyValidator validator =
new NetworkIdConsistencyValidator(
routeTableContainer, routeNetworkTableContainer, networkTableContainer);
validator.validate(noticeContainer);
assertThat(noticeContainer.getValidationNotices().isEmpty());
}

@Test
public void validatesConditionalForbiddenFilePresence1() {
routeNetworkTableContainer =
GtfsRouteNetworkTableContainer.forEntities(
ImmutableList.of(
new GtfsRouteNetwork.Builder().setRouteId("123").setNetworkId("network1").build()),
noticeContainer);
NetworkIdConsistencyValidator validator =
new NetworkIdConsistencyValidator(
routeTableContainer, routeNetworkTableContainer, networkTableContainer);
validator.validate(noticeContainer);
assertThat(noticeContainer.getValidationNotices().size() == 1);
NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice notice =
(NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice)
noticeContainer.getValidationNotices().get(0);
NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice expectedNotice =
new NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice(
"routes.txt", "route_networks.txt", "network_id");
assertThat(notice.toString().equals(expectedNotice.toString()));
}

@Test
public void validatesConditionalForbiddenFilePresence2() {
networkTableContainer =
GtfsNetworkTableContainer.forEntities(
ImmutableList.of(new GtfsNetwork.Builder().setNetworkId("network1").build()),
noticeContainer);
NetworkIdConsistencyValidator validator =
new NetworkIdConsistencyValidator(
routeTableContainer, routeNetworkTableContainer, networkTableContainer);
validator.validate(noticeContainer);
assertThat(noticeContainer.getValidationNotices().size() == 1);
NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice notice =
(NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice)
noticeContainer.getValidationNotices().get(0);
NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice expectedNotice =
new NetworkIdConsistencyValidator.RouteNetworksSpecifiedInMoreThanOneFileNotice(
"routes.txt", "networks.txt", "network_id");
assertThat(notice.toString().equals(expectedNotice.toString()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ public void testNoticeClassFieldNames() {
"validator",
"value",
"maxShapeDistanceTraveled",
"maxTripDistanceTraveled");
"maxTripDistanceTraveled",
"fileNameA",
"fileNameB");
}

private static List<String> discoverValidationNoticeFieldNames() {
Expand Down

0 comments on commit 6f69f45

Please sign in to comment.