diff --git a/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/CalendarDateVerificationService.java b/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/CalendarDateVerificationService.java index 86e0748..78de424 100644 --- a/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/CalendarDateVerificationService.java +++ b/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/CalendarDateVerificationService.java @@ -6,12 +6,15 @@ import java.util.Calendar; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + import org.onebusaway.gtfs.impl.GtfsRelationalDaoImpl; import org.onebusaway.gtfs.impl.calendar.CalendarServiceDataFactoryImpl; import org.onebusaway.gtfs.model.Agency; @@ -155,6 +158,10 @@ public TreeMap> getServiceIdsForDates(){ return serviceIdsForDates; } + + public HashSet getActiveServiceIdsOnly(){ + return getServiceIdsForDates().values().stream().collect(HashSet::new, HashSet::addAll, HashSet::addAll); + } public ArrayList getDatesWithNoTrips(){ ArrayList datesWithNoTrips = new ArrayList(); @@ -198,7 +205,7 @@ public String getTripDataForEveryDay(){ ServiceIdHelper helper = new ServiceIdHelper(); SimpleDateFormat df = new SimpleDateFormat("E, yyyy-MM-dd"); Calendar yesterday = Calendar.getInstance(); - yesterday.add(Calendar.DAY_OF_MONTH, -1);; + yesterday.add(Calendar.DAY_OF_MONTH, -1); TreeMap tc = getTripCountForDates(); for(Calendar d: tc.keySet()){ diff --git a/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/GtfsValidationService.java b/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/GtfsValidationService.java index 7411cd7..e03b40d 100644 --- a/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/GtfsValidationService.java +++ b/gtfs-validation-lib/src/main/java/com/conveyal/gtfs/service/GtfsValidationService.java @@ -21,6 +21,7 @@ import org.onebusaway.gtfs.model.StopTime; import org.onebusaway.gtfs.model.Trip; +import com.conveyal.gtfs.GtfsStatisticsServiceCalendarDatesTest; import com.conveyal.gtfs.model.BlockInterval; import com.conveyal.gtfs.model.DuplicateStops; import com.conveyal.gtfs.model.InputOutOfRange; @@ -42,6 +43,7 @@ public class GtfsValidationService { private GtfsRelationalDaoImpl gtfsDao = null; private GtfsStatisticsService statsService = null; + private CalendarDateVerificationService cdvs = null; public GtfsValidationService(GtfsRelationalDaoImpl dao) { @@ -109,7 +111,6 @@ public ValidationResult validateTrips() { ValidationResult result = new ValidationResult(); - // map stop time sequences to trip id HashMap> tripStopTimes = new HashMap>(statsService.getStopTimesCount() *2); @@ -117,6 +118,10 @@ public ValidationResult validateTrips() { HashSet usedStopIds = new HashSet(statsService.getStopCount() *2); String tripId; + + cdvs = new CalendarDateVerificationService(gtfsDao); + HashSet activeServiceIds = cdvs.getActiveServiceIdsOnly(); + for(StopTime stopTime : gtfsDao.getAllStopTimes()) { @@ -133,12 +138,12 @@ public ValidationResult validateTrips() { } - // create service calendar date map - - +// // create service calendar date map +// +// @SuppressWarnings("deprecation") int reasonableNumberOfDates = statsService.getNumberOfDays() *2; - + HashMap> serviceCalendarDates = new HashMap>(reasonableNumberOfDates); //TODO: factor out. for(ServiceCalendar calendar : gtfsDao.getAllCalendars()) { @@ -273,10 +278,11 @@ else if (exceptionType == 1) { blockId = ""; - if(trip.getBlockId() != null) + if(trip.getBlockId() != null){ blockId = trip.getBlockId(); + } - if(!blockId.isEmpty()) { + if(!blockId.isEmpty() && activeServiceIds.contains(trip.getServiceId())) { BlockInterval blockInterval = new BlockInterval(); blockInterval.setTrip(trip); @@ -313,64 +319,67 @@ else if (exceptionType == 1) { } else duplicateTripHash.put(tripKey, tripId); - - } + // check for overlapping trips within block + for(Entry> blockIdset : blockIntervals.entrySet()) { - for(Entry> blockIdset : blockIntervals.entrySet()) { - - blockId = blockIdset.getKey(); - ArrayList intervals = blockIntervals.get(blockId); + blockId = blockIdset.getKey(); + ArrayList intervals = blockIntervals.get(blockId); - Collections.sort(intervals, new BlockIntervalComparator()); + Collections.sort(intervals, new BlockIntervalComparator()); - int iOffset = 0; - for(BlockInterval i1 : intervals) { - for(BlockInterval i2 : intervals.subList(iOffset, intervals.size() - 1)) { + int iOffset = 0; + for(BlockInterval i1 : intervals) { + for(BlockInterval i2 : intervals.subList(iOffset, intervals.size() - 1)) { - String tripId1 = i1.getTrip().getId().toString(); - String tripId2 = i2.getTrip().getId().toString(); + String tripId1 = i1.getTrip().getId().toString(); + String tripId2 = i2.getTrip().getId().toString(); - if(!tripId1.equals(tripId2)) { - // if trips don't overlap, skip - if(i1.getLastStop().getDepartureTime() <= i2.getFirstStop().getArrivalTime() - || i2.getLastStop().getDepartureTime() <= i1.getFirstStop().getArrivalTime()) - continue; - - // if trips have same service id they overlap - if(i1.getTrip().getServiceId().getId().equals(i2.getTrip().getServiceId().getId())) { - // but if they are already in the result set, ignore - if (!result.containsBoth(tripId1, tripId2, "trip")){ - InvalidValue iv = - new InvalidValue("trip", "block_id", blockId, "OverlappingTripsInBlock", "Trip Ids " + tripId1 + " & " + tripId2 + " overlap and share block Id " + blockId , null, Priority.HIGH); - // not strictly correct; they could be on different routes - iv.route = i1.getTrip().getRoute(); - result.add(iv); - } - } - - else { - // if trips don't share service id check to see if service dates fall on the same days/day of week - - for(Date d1 : serviceCalendarDates.get(i1.getTrip().getServiceId().getId())) { + if(!tripId1.equals(tripId2)) { + // if trips don't overlap, skip + if(i1.getLastStop().getDepartureTime() <= i2.getFirstStop().getArrivalTime() + || i2.getLastStop().getDepartureTime() <= i1.getFirstStop().getArrivalTime()) + continue; - if(serviceCalendarDates.get(i2.getTrip().getServiceId().getId()).contains(d1)) { - InvalidValue iv = new InvalidValue("trip", "block_id", blockId, "OverlappingTripsInBlock", "Trip Ids " + tripId1 + " & " + tripId2 + " overlap and share block Id " + blockId , null, Priority.HIGH); + // if trips have same service id they overlap + if(i1.getTrip().getServiceId().getId().equals(i2.getTrip().getServiceId().getId())) { + // but if they are already in the result set, ignore + if (!result.containsBoth(tripId1, tripId2, "trip")){ + InvalidValue iv = + new InvalidValue("trip", "block_id", blockId, "OverlappingTripsInBlock", "Trip Ids " + tripId1 + " & " + tripId2 + " overlap and share block Id " + blockId , null, Priority.HIGH); + // not strictly correct; they could be on different routes iv.route = i1.getTrip().getRoute(); result.add(iv); - break; + } + } + + else { + // if trips don't share service id check to see if service dates fall on the same days/day of week + +// try { + + for(Date d1 : serviceCalendarDates.get(i1.getTrip().getServiceId().getId())) { + + if(serviceCalendarDates.get(i2.getTrip().getServiceId().getId()).contains(d1)) { + InvalidValue iv = new InvalidValue("trip", "block_id", blockId, "OverlappingTripsInBlock", "Trip Ids " + tripId1 + " & " + tripId2 + " overlap and share block Id " + blockId , null, Priority.HIGH); + iv.route = i1.getTrip().getRoute(); + result.add(iv); + break; + } +// } + //} catch (Exception e) { + //System.out.println("Could not find :"+ i1.getTrip().getServiceId().getId().toString()); } } } } } } - } - + // check for reversed trip shapes and add to result list result.append(this.listReversedTripShapes()); diff --git a/gtfs-validation-lib/src/test/java/com/conveyal/gtfs/ValidateTripsWasFailingBlocksTest.java b/gtfs-validation-lib/src/test/java/com/conveyal/gtfs/ValidateTripsWasFailingBlocksTest.java new file mode 100644 index 0000000..670b6b0 --- /dev/null +++ b/gtfs-validation-lib/src/test/java/com/conveyal/gtfs/ValidateTripsWasFailingBlocksTest.java @@ -0,0 +1,57 @@ +package com.conveyal.gtfs; + +import java.io.File; +import java.util.HashSet; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.onebusaway.csv_entities.exceptions.MissingRequiredFieldException; +import org.onebusaway.gtfs.impl.GtfsRelationalDaoImpl; +import org.onebusaway.gtfs.model.AgencyAndId; +import org.onebusaway.gtfs.serialization.GtfsReader; + +import com.conveyal.gtfs.model.ValidationResult; +import com.conveyal.gtfs.service.CalendarDateVerificationService; +import com.conveyal.gtfs.service.GtfsValidationService; + +import junit.framework.Assert; + +public class ValidateTripsWasFailingBlocksTest extends UnitTestBaseUtil { + static GtfsValidationService gtfsValidation1 = null; + static GtfsRelationalDaoImpl gtfsMDao = null; + static MissingRequiredFieldException mrf = null; + static CalendarDateVerificationService cdvs = null; + + @BeforeClass + public static void setUpClass() { + gtfsMDao = new GtfsRelationalDaoImpl(); + GtfsReader gtfsReader1 = new GtfsReader(); + + try { + + File gtfsFile1 = new File("src/test/resources/GTFS_MTABC_A7_SCS.zip"); + gtfsReader1.setInputLocation(gtfsFile1); + gtfsReader1.setEntityStore(gtfsMDao); + gtfsReader1.run(); + + gtfsValidation1 = new GtfsValidationService(gtfsMDao); + cdvs = new CalendarDateVerificationService(gtfsMDao); + + + } catch (Exception e) { + e.printStackTrace(); + } + } + @Test + public void validateTrips() { + ValidationResult result = gtfsValidation1.validateTrips(); + Assert.assertEquals(0,result.invalidValues.size()); + } + + @Test + public void testListOfActiveServiceIds(){ + Assert.assertTrue(cdvs.getActiveServiceIdsOnly().size() == 1); + } + + +} diff --git a/gtfs-validation-lib/src/test/resources/GTFS_MTABC_A7_SCS.zip b/gtfs-validation-lib/src/test/resources/GTFS_MTABC_A7_SCS.zip new file mode 100644 index 0000000..f451cbe Binary files /dev/null and b/gtfs-validation-lib/src/test/resources/GTFS_MTABC_A7_SCS.zip differ