Skip to content

Commit

Permalink
feat: validator for ferry trips + bikes allowance (#1510)
Browse files Browse the repository at this point in the history
* feat: validator for ferry trips + bike allocation

* feat: removed "info" suffix

* feat: fixed formatting
  • Loading branch information
cka-y authored and davidgamez committed Jul 5, 2023
1 parent b05ce53 commit ce80db2
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public interface GtfsRouteSchema extends GtfsEntity {
String routeDesc();

@Required
@Index
GtfsRouteType routeType();

@FieldType(FieldTypeEnum.URL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public interface GtfsTripSchema extends GtfsEntity {
@FieldType(FieldTypeEnum.ID)
@Required
@ForeignKey(table = "routes.txt", field = "route_id")
@Index
String routeId();

@FieldType(FieldTypeEnum.ID)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2021 MobilityData IO
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mobilitydata.gtfsvalidator.validator;

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

import java.util.List;
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.*;

/**
* Validates that bikes_allowed information is present for ferry trips
*
* <p>Generated notice: {@link MissingBikeAllowanceNotice}.
*/
@GtfsValidator
public class BikesAllowanceValidator extends FileValidator {

private final GtfsTripTableContainer tripTable;

private final GtfsRouteTableContainer routeTable;

@Inject
BikesAllowanceValidator(GtfsTripTableContainer tripTable, GtfsRouteTableContainer routeTable) {
this.tripTable = tripTable;
this.routeTable = routeTable;
}

@Override
public void validate(NoticeContainer noticeContainer) {
List<GtfsRoute> routes = routeTable.byRouteType(GtfsRouteType.FERRY);
for (GtfsRoute route : routes) {
List<GtfsTrip> trips = tripTable.byRouteId(route.routeId());
for (GtfsTrip trip : trips) {
if (trip.bikesAllowed() != GtfsBikesAllowed.UNRECOGNIZED
&& trip.bikesAllowed() != GtfsBikesAllowed.UNKNOWN) {
continue;
}
noticeContainer.addValidationNotice(
new MissingBikeAllowanceNotice(trip.csvRowNumber(), trip.routeId(), trip.tripId()));
}
}
}

/**
* Ferry trips should include bike allowance information.
*
* <p>All ferry trips should have a valid value in the bikes_allowed field in trips.txt.
*/
@GtfsValidationNotice(
severity = WARNING,
files = @FileRefs({GtfsRouteSchema.class, GtfsTripSchema.class}))
static class MissingBikeAllowanceNotice extends ValidationNotice {

/** The row number of the faulty record. */
private final int csvRowNumber;

/** The faulty record's route id. */
private final String routeId;

/** The faulty record's trip id. */
private final String tripId;

MissingBikeAllowanceNotice(int csvRowNumber, String routeId, String tripId) {
this.csvRowNumber = csvRowNumber;
this.routeId = routeId;
this.tripId = tripId;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.mobilitydata.gtfsvalidator.validator;

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

import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
import org.mobilitydata.gtfsvalidator.table.*;

@RunWith(JUnit4.class)
public class BikeAllowanceValidatorTest {

private static List<GtfsTrip> createTripTable(
String routeId, String serviceId, GtfsBikesAllowed bikesAllowed, int rows) {
ArrayList<GtfsTrip> trips = new ArrayList<>();
for (int i = 0; i < rows; i++) {
trips.add(
new GtfsTrip.Builder()
.setCsvRowNumber(i + 1)
.setTripId("t" + i)
.setServiceId(serviceId)
.setRouteId(routeId)
.setBikesAllowed(bikesAllowed)
.build());
}
return trips;
}

private static List<GtfsRoute> createRouteTable(String routeId, GtfsRouteType routeType) {
return List.of(
new GtfsRoute.Builder()
.setCsvRowNumber(1)
.setRouteId(routeId)
.setRouteType(routeType)
.build());
}

private static List<ValidationNotice> generateNotices(
List<GtfsTrip> trips, List<GtfsRoute> routes) {
NoticeContainer noticeContainer = new NoticeContainer();
new BikesAllowanceValidator(
GtfsTripTableContainer.forEntities(trips, noticeContainer),
GtfsRouteTableContainer.forEntities(routes, noticeContainer))
.validate(noticeContainer);
return noticeContainer.getValidationNotices();
}

@Test
public void testValidFeedForFerryTrips() {
assertThat(
generateNotices(
createTripTable("route1", "service1", GtfsBikesAllowed.ALLOWED, 2),
createRouteTable("route1", GtfsRouteType.FERRY)))
.isEmpty();
}

@Test
public void testValidFeedForNonFerryTrips() {
assertThat(
generateNotices(
createTripTable("route1", "service1", GtfsBikesAllowed.UNRECOGNIZED, 2),
createRouteTable("route1", GtfsRouteType.BUS)))
.isEmpty();
assertThat(
generateNotices(
createTripTable("route1", "service1", null, 2),
createRouteTable("route1", GtfsRouteType.BUS)))
.isEmpty();
}

@Test
public void testInvalidBikesAllowedValueForFerryTrips() {
assertThat(
generateNotices(
createTripTable("route1", "service1", GtfsBikesAllowed.UNRECOGNIZED, 2),
createRouteTable("route1", GtfsRouteType.FERRY)))
.hasSize(2);
assertThat(
generateNotices(
createTripTable("route1", "service1", null, 2),
createRouteTable("route1", GtfsRouteType.FERRY)))
.hasSize(2);
}
}

0 comments on commit ce80db2

Please sign in to comment.