Skip to content

Commit

Permalink
feat(validator): validate stop names and trip headsigns
Browse files Browse the repository at this point in the history
refs #167
  • Loading branch information
landonreed committed Dec 19, 2018
1 parent cab706f commit 57566ec
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/main/java/com/conveyal/gtfs/error/NewGTFSErrorType.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ public enum NewGTFSErrorType {
SERVICE_NEVER_ACTIVE(Priority.MEDIUM, "A service code was defined, but is never active on any date."),
SERVICE_UNUSED(Priority.MEDIUM, "A service code was defined, but is never referenced by any trips."),
SHAPE_DIST_TRAVELED_NOT_INCREASING(Priority.MEDIUM, "Shape distance traveled must increase with stop times."),
STOP_DESCRIPTION_SAME_AS_NAME(Priority.LOW, "The description of a stop is identical to its name, so does not add any information."),
STOP_LOW_POPULATION_DENSITY(Priority.HIGH, "A stop is located in a geographic area with very low human population density."),
STOP_NAME_MISSING(Priority.MEDIUM, "A stop does not have a name."),
STOP_GEOGRAPHIC_OUTLIER(Priority.HIGH, "This stop is located very far from the middle 90% of stops in this feed."),
STOP_UNUSED(Priority.MEDIUM, "This stop is not referenced by any trips."),
TRIP_EMPTY(Priority.HIGH, "This trip is defined but has no stop times."),
TRIP_HEADSIGN_CONTAINS_ROUTE_NAME(Priority.LOW, "A trip headsign contains the route name, but should only contain information to distinguish it from other trips for the route."),
TRIP_HEADSIGN_SHOULD_DESCRIBE_DESTINATION_OR_WAYPOINTS(Priority.LOW, "A trip headsign begins with 'to' or 'towards', but should begin with destination or direction and optionally include waypoints with 'via'"),
TRIP_NEVER_ACTIVE(Priority.MEDIUM, "A trip is defined, but its service is never running on any date."),
ROUTE_UNUSED(Priority.HIGH, "This route is defined but has no trips."),
TRAVEL_DISTANCE_ZERO(Priority.MEDIUM, "The vehicle does not cover any distance between the last stop and this one."),
Expand Down
38 changes: 37 additions & 1 deletion src/main/java/com/conveyal/gtfs/validator/NamesValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.conveyal.gtfs.error.SQLErrorStorage;
import com.conveyal.gtfs.loader.Feed;
import com.conveyal.gtfs.model.Route;
import com.conveyal.gtfs.model.Stop;
import com.conveyal.gtfs.model.Trip;

import static com.conveyal.gtfs.error.NewGTFSErrorType.*;

Expand Down Expand Up @@ -41,7 +43,41 @@ public void validate() {
// TODO we want some additional checking for extended route types.
}
}
// TODO Check trips and all other tables.
// Check stops
for (Stop stop : feed.stops) {
String name = normalize(stop.stop_name);
String desc = normalize(stop.stop_desc);
// Stops must be named.
if (name.isEmpty()) {
registerError(stop, STOP_NAME_MISSING);
}
// If provided, the description of a stop should be more informative than its name.
if (!desc.isEmpty() && desc.equals(name)) {
registerError(stop, STOP_DESCRIPTION_SAME_AS_NAME, desc);
}
}
// Check trips
for (Trip trip : feed.trips) {
String headsign = normalize(trip.trip_headsign);
// TODO: check trip short name?
// String shortName = normalize(trip.trip_short_name);
Route route = feed.routes.get(trip.route_id);
String routeShortName = "", routeLongName = "";
if (route != null) {
routeShortName = normalize(route.route_short_name);
routeLongName = normalize(route.route_long_name);
}
// Trip headsign should not duplicate route name.
if (!headsign.isEmpty() && (headsign.contains(routeShortName) || headsign.contains(routeLongName))) {
registerError(trip, TRIP_HEADSIGN_CONTAINS_ROUTE_NAME, headsign);
}
// Trip headsign should not begin with "to" or "towards" (note: headsign normalized to lowercase). Headsigns
// should follow one of the patterns defined in the best practices: http://gtfs.org/best-practices#tripstxt
if (headsign.startsWith("to ") || headsign.startsWith("towards ")) {
registerError(trip, TRIP_HEADSIGN_SHOULD_DESCRIBE_DESTINATION_OR_WAYPOINTS, headsign);
}
}
// TODO Are there other tables we're not checking?
}

/** @return a non-null String that is lower case and has no leading or trailing whitespace */
Expand Down

0 comments on commit 57566ec

Please sign in to comment.