diff --git a/src/test/java/org/opentripplanner/apis/gtfs/mapping/CarsAllowedMapperTest.java b/src/test/java/org/opentripplanner/apis/gtfs/mapping/CarsAllowedMapperTest.java new file mode 100644 index 00000000000..a2a1b40a5e8 --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/mapping/CarsAllowedMapperTest.java @@ -0,0 +1,21 @@ +package org.opentripplanner.apis.gtfs.mapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import org.junit.jupiter.api.Test; +import org.opentripplanner.transit.model.network.CarAccess; + +class CarsAllowedMapperTest { + + @Test + void mapping() { + Arrays + .stream(CarAccess.values()) + .filter(ba -> ba != CarAccess.UNKNOWN) + .forEach(d -> { + var mapped = CarsAllowedMapper.map(d); + assertEquals(d.toString(), mapped.toString()); + }); + } +} diff --git a/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java b/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java index 06b10575ef9..e5f77f57659 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java @@ -9,12 +9,14 @@ import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN; import static org.opentripplanner.transit.model._data.TransitModelForTest.id; +import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; import org.opentripplanner.ext.flex.trip.UnscheduledTrip; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; +import org.opentripplanner.model.StopTime; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.Edge; @@ -23,7 +25,15 @@ import org.opentripplanner.street.model.vertex.TransitStopVertex; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.Deduplicator; +import org.opentripplanner.transit.model.network.CarAccess; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.network.StopPattern; +import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; +import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.model.timetable.TripTimesFactory; import org.opentripplanner.transit.service.StopModel; import org.opentripplanner.transit.service.TransitModel; @@ -92,6 +102,37 @@ void linkFlexStop() { }); } + @Test + void linkCarsAllowedStop() { + var model = new TestModel(); + var carsAllowedTrip = TransitModelForTest + .of() + .trip("carsAllowedTrip") + .withCarsAllowed(CarAccess.ALLOWED) + .build(); + model.withCarsAllowedTrip(carsAllowedTrip, model.stop()); + + var module = model.streetLinkerModule(); + + module.buildGraph(); + + assertTrue(model.stopVertex().isConnectedToGraph()); + + // Because the stop is used by a carsAllowed trip it needs to be linked to both the walk and car edge + assertEquals(2, model.stopVertex().getOutgoing().size()); + var linkToWalk = model.outgoingLinks().getFirst(); + SplitterVertex walkSplit = (SplitterVertex) linkToWalk.getToVertex(); + + assertTrue(walkSplit.isConnectedToWalkingEdge()); + assertFalse(walkSplit.isConnectedToDriveableEdge()); + + var linkToCar = model.outgoingLinks().getLast(); + SplitterVertex carSplit = (SplitterVertex) linkToCar.getToVertex(); + + assertFalse(carSplit.isConnectedToWalkingEdge()); + assertTrue(carSplit.isConnectedToDriveableEdge()); + } + private static class TestModel { private final TransitStopVertex stopVertex; @@ -155,5 +196,33 @@ public RegularStop stop() { public void withFlexTrip(UnscheduledTrip flexTrip) { transitModel.addFlexTrip(flexTrip.getId(), flexTrip); } + + public void withCarsAllowedTrip(Trip trip, StopLocation... stops) { + Route route = TransitModelForTest.route("carsAllowedRoute").build(); + var stopTimes = Arrays + .stream(stops) + .map(s -> { + var stopTime = new StopTime(); + stopTime.setStop(s); + stopTime.setArrivalTime(30); + stopTime.setDepartureTime(60); + stopTime.setTrip(trip); + return stopTime; + }) + .toList(); + StopPattern stopPattern = new StopPattern(stopTimes); + TripPattern tripPattern = TransitModelForTest + .tripPattern("carsAllowedTripPattern", route) + .withStopPattern(stopPattern) + .build(); + RealTimeTripTimes tripTimes = TripTimesFactory.tripTimes( + trip, + stopTimes, + transitModel.getDeduplicator() + ); + + tripPattern.add(tripTimes); + transitModel.addTripPattern(tripPattern.getId(), tripPattern); + } } } diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/CarAccessMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/CarAccessMapperTest.java new file mode 100644 index 00000000000..a312d9967d6 --- /dev/null +++ b/src/test/java/org/opentripplanner/gtfs/mapping/CarAccessMapperTest.java @@ -0,0 +1,26 @@ +package org.opentripplanner.gtfs.mapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.onebusaway.gtfs.model.Route; +import org.onebusaway.gtfs.model.Trip; +import org.opentripplanner.transit.model.network.CarAccess; + +public class CarAccessMapperTest { + + private static final int CARS_ALLOWED = 1; + private static final int CARS_NOT_ALLOWED = 2; + + @Test + public void testTripProvidedValues() { + Trip trip = new Trip(); + assertEquals(CarAccess.UNKNOWN, CarAccessMapper.mapForTrip(trip)); + + trip.setCarsAllowed(CARS_ALLOWED); + assertEquals(CarAccess.ALLOWED, CarAccessMapper.mapForTrip(trip)); + + trip.setCarsAllowed(CARS_NOT_ALLOWED); + assertEquals(CarAccess.NOT_ALLOWED, CarAccessMapper.mapForTrip(trip)); + } +} diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java index 964c3d8155e..98f5519926c 100644 --- a/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java +++ b/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java @@ -14,6 +14,7 @@ import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.transit.model.basic.Accessibility; import org.opentripplanner.transit.model.network.BikeAccess; +import org.opentripplanner.transit.model.network.CarAccess; import org.opentripplanner.transit.model.timetable.Direction; public class TripMapperTest { @@ -21,6 +22,7 @@ public class TripMapperTest { private static final String FEED_ID = "FEED"; private static final AgencyAndId AGENCY_AND_ID = new AgencyAndId("A", "1"); private static final int BIKES_ALLOWED = 1; + private static final int CARS_ALLOWED = 1; private static final String BLOCK_ID = "Block Id"; private static final int DIRECTION_ID = 1; private static final String TRIP_HEADSIGN = "Trip Headsign"; @@ -47,6 +49,7 @@ private static TripMapper defaultTripMapper() { TRIP.setId(AGENCY_AND_ID); TRIP.setBikesAllowed(BIKES_ALLOWED); + TRIP.setCarsAllowed(CARS_ALLOWED); TRIP.setBlockId(BLOCK_ID); TRIP.setDirectionId(Integer.toString(DIRECTION_ID)); TRIP.setRoute(data.route); @@ -78,6 +81,7 @@ void testMap() throws Exception { assertEquals(TRIP_SHORT_NAME, result.getShortName()); assertEquals(Accessibility.POSSIBLE, result.getWheelchairBoarding()); assertEquals(BikeAccess.ALLOWED, result.getBikesAllowed()); + assertEquals(CarAccess.ALLOWED, result.getCarsAllowed()); } @Test @@ -99,6 +103,7 @@ void testMapWithNulls() throws Exception { assertEquals(Direction.UNKNOWN, result.getDirection()); assertEquals(Accessibility.NO_INFORMATION, result.getWheelchairBoarding()); assertEquals(BikeAccess.UNKNOWN, result.getBikesAllowed()); + assertEquals(CarAccess.UNKNOWN, result.getCarsAllowed()); } /** Mapping the same object twice, should return the same instance. */ diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java index be6266ccdbe..c5dea627d5a 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java @@ -34,6 +34,7 @@ import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.BikeAccess; +import org.opentripplanner.transit.model.network.CarAccess; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.RouteBuilder; import org.opentripplanner.transit.model.network.RoutingTripPattern; @@ -107,6 +108,7 @@ void testWheelchairAccess(Accessibility wheelchair, WheelchairPreferences access .getRoutingTripPattern(); var filter = new RouteRequestTransitDataProviderFilter( + false, false, true, accessibility, @@ -157,6 +159,7 @@ void testRealtimeCancelledStops(boolean includeRealtimeCancellations) { .getRoutingTripPattern(); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -202,6 +205,7 @@ void notFilteringExpectedTripPatternForDateTest() { TripPatternForDate tripPatternForDate = createTestTripPatternForDate(); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -221,6 +225,7 @@ void bannedRouteFilteringTest() { TripPatternForDate tripPatternForDate = createTestTripPatternForDate(); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -246,6 +251,7 @@ void bannedTripFilteringTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -253,6 +259,7 @@ void bannedTripFilteringTest() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -281,6 +288,7 @@ void matchModeFilterAndBannedAgencyFilter() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -316,6 +324,7 @@ void matchCombinedModesAndBannedAgencyFilter() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -347,6 +356,7 @@ void matchSelectedAgencyExcludedSubMode() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -386,6 +396,7 @@ void transitModeFilteringTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, TransmodelTransportSubmode.LOCAL_BUS.getValue(), Accessibility.NOT_POSSIBLE, @@ -412,6 +423,7 @@ void notFilteringExpectedTripTimesTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -419,6 +431,7 @@ void notFilteringExpectedTripTimesTest() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -439,6 +452,36 @@ void bikesAllowedFilteringTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, + TransitMode.BUS, + null, + Accessibility.NOT_POSSIBLE, + null + ); + + var filter = new RouteRequestTransitDataProviderFilter( + true, + false, + true, + WheelchairPreferences.DEFAULT, + false, + false, + Set.of(), + List.of(AllowAllTransitFilter.of()) + ); + + boolean valid = filter.tripTimesPredicate(tripTimes, true); + + assertFalse(valid); + } + + @Test + void carsAllowedFilteringTest() { + TripTimes tripTimes = createTestTripTimes( + TRIP_ID, + ROUTE, + BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -446,6 +489,7 @@ void bikesAllowedFilteringTest() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, true, true, WheelchairPreferences.DEFAULT, @@ -466,6 +510,7 @@ void removeInaccessibleTrip() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -473,6 +518,7 @@ void removeInaccessibleTrip() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, true, WheelchairPreferences.DEFAULT, @@ -493,6 +539,7 @@ void keepAccessibleTrip() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.POSSIBLE, @@ -500,6 +547,7 @@ void keepAccessibleTrip() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, true, WheelchairPreferences.DEFAULT, @@ -520,6 +568,7 @@ void keepRealTimeAccessibleTrip() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -527,6 +576,7 @@ void keepRealTimeAccessibleTrip() { ); var filter = new RouteRequestTransitDataProviderFilter( + false, false, true, WheelchairPreferences.DEFAULT, @@ -549,6 +599,7 @@ void includePlannedCancellationsTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -558,6 +609,7 @@ void includePlannedCancellationsTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -566,6 +618,7 @@ void includePlannedCancellationsTest() { // Given var filter1 = new RouteRequestTransitDataProviderFilter( + false, false, false, WheelchairPreferences.DEFAULT, @@ -587,6 +640,7 @@ void includePlannedCancellationsTest() { // Given var filter2 = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -613,6 +667,7 @@ void includeRealtimeCancellationsTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -623,6 +678,7 @@ void includeRealtimeCancellationsTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -632,6 +688,7 @@ void includeRealtimeCancellationsTest() { // Given var filter1 = new RouteRequestTransitDataProviderFilter( + false, false, false, WheelchairPreferences.DEFAULT, @@ -653,6 +710,7 @@ void includeRealtimeCancellationsTest() { // Given var filter2 = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -709,12 +767,34 @@ void testBikesAllowed() { ); } + @Test + void testCarsAllowed() { + RouteBuilder routeBuilder = TransitModelForTest.route("1"); + TripBuilder trip = Trip.of(TransitModelForTest.id("T1")).withRoute(routeBuilder.build()); + + assertEquals( + CarAccess.UNKNOWN, + RouteRequestTransitDataProviderFilter.carAccessForTrip(trip.build()) + ); + trip.withCarsAllowed(CarAccess.ALLOWED); + assertEquals( + CarAccess.ALLOWED, + RouteRequestTransitDataProviderFilter.carAccessForTrip(trip.build()) + ); + trip.withCarsAllowed(CarAccess.NOT_ALLOWED); + assertEquals( + CarAccess.NOT_ALLOWED, + RouteRequestTransitDataProviderFilter.carAccessForTrip(trip.build()) + ); + } + @Test void multipleFilteringTest() { TripTimes matchingTripTimes = createTestTripTimes( TRIP_ID, ROUTE, BikeAccess.ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.POSSIBLE, @@ -724,6 +804,7 @@ void multipleFilteringTest() { TRIP_ID, ROUTE, BikeAccess.ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.RAIL, null, Accessibility.POSSIBLE, @@ -733,6 +814,7 @@ void multipleFilteringTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.RAIL, null, Accessibility.POSSIBLE, @@ -742,6 +824,7 @@ void multipleFilteringTest() { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.RAIL, null, Accessibility.NOT_POSSIBLE, @@ -751,6 +834,7 @@ void multipleFilteringTest() { TRIP_ID, ROUTE, BikeAccess.ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.NOT_POSSIBLE, @@ -760,6 +844,7 @@ void multipleFilteringTest() { TRIP_ID, ROUTE, BikeAccess.ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, null, Accessibility.POSSIBLE, @@ -768,6 +853,7 @@ void multipleFilteringTest() { var filter = new RouteRequestTransitDataProviderFilter( true, + false, true, DEFAULT_ACCESSIBILITY, false, @@ -790,6 +876,7 @@ private boolean validateModesOnTripTimes( TripTimes tripTimes ) { var filter = new RouteRequestTransitDataProviderFilter( + false, false, false, DEFAULT_ACCESSIBILITY, @@ -867,6 +954,7 @@ private RealTimeTripTimes createTestTripTimes( FeedScopedId tripId, Route route, BikeAccess bikeAccess, + CarAccess carAccess, TransitMode mode, String submode, Accessibility wheelchairBoarding, @@ -878,6 +966,7 @@ private RealTimeTripTimes createTestTripTimes( .withMode(mode) .withNetexSubmode(submode) .withBikesAllowed(bikeAccess) + .withCarsAllowed(carAccess) .withWheelchairBoarding(wheelchairBoarding) .withNetexAlteration(tripAlteration) .build(); @@ -896,6 +985,7 @@ private TripTimes createTestTripTimesWithSubmode(String submode) { TRIP_ID, ROUTE, BikeAccess.NOT_ALLOWED, + CarAccess.NOT_ALLOWED, TransitMode.BUS, submode, Accessibility.NOT_POSSIBLE, diff --git a/src/test/java/org/opentripplanner/transit/model/timetable/TripTest.java b/src/test/java/org/opentripplanner/transit/model/timetable/TripTest.java index 3a3f35643fa..eeaa979257d 100644 --- a/src/test/java/org/opentripplanner/transit/model/timetable/TripTest.java +++ b/src/test/java/org/opentripplanner/transit/model/timetable/TripTest.java @@ -12,6 +12,7 @@ import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.BikeAccess; +import org.opentripplanner.transit.model.network.CarAccess; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.organization.Operator; @@ -24,6 +25,7 @@ class TripTest { private static final Direction DIRECTION = Direction.INBOUND; public static final NonLocalizedString HEAD_SIGN = new NonLocalizedString("head sign"); private static final BikeAccess BIKE_ACCESS = BikeAccess.ALLOWED; + private static final CarAccess CAR_ACCESS = CarAccess.ALLOWED; private static final TransitMode TRANSIT_MODE = TransitMode.BUS; private static final String BLOCK_ID = "blockId"; private static final TripAlteration TRIP_ALTERATION = TripAlteration.CANCELLATION; @@ -43,6 +45,7 @@ class TripTest { .withDirection(DIRECTION) .withHeadsign(HEAD_SIGN) .withBikesAllowed(BIKE_ACCESS) + .withCarsAllowed(CAR_ACCESS) .withMode(TRANSIT_MODE) .withGtfsBlockId(BLOCK_ID) .withNetexAlteration(TRIP_ALTERATION) @@ -84,6 +87,7 @@ void copy() { assertEquals(DIRECTION, copy.getDirection()); assertEquals(HEAD_SIGN, copy.getHeadsign()); assertEquals(BIKE_ACCESS, copy.getBikesAllowed()); + assertEquals(CAR_ACCESS, copy.getCarsAllowed()); assertEquals(TRANSIT_MODE, copy.getMode()); assertEquals(BLOCK_ID, copy.getGtfsBlockId()); assertEquals(TRIP_ALTERATION, copy.getNetexAlteration()); @@ -110,6 +114,7 @@ void sameAs() { assertFalse(subject.sameAs(subject.copy().withDirection(Direction.OUTBOUND).build())); assertFalse(subject.sameAs(subject.copy().withHeadsign(new NonLocalizedString("X")).build())); assertFalse(subject.sameAs(subject.copy().withBikesAllowed(BikeAccess.NOT_ALLOWED).build())); + assertFalse(subject.sameAs(subject.copy().withCarsAllowed(CarAccess.NOT_ALLOWED).build())); assertFalse(subject.sameAs(subject.copy().withMode(TransitMode.RAIL).build())); assertFalse(subject.sameAs(subject.copy().withGtfsBlockId("X").build())); assertFalse(