From 897af2c06f3ba8b322a7bb3f4315a7d673238b9e Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 1 May 2023 22:32:42 +0200 Subject: [PATCH 001/183] Extract GTFS zip files, rename dropoff to drop_off --- .../opentripplanner/ext/flex/FlexTest.java | 6 +- .../flex/trip/ScheduledDeviatedTripTest.java | 2 +- .../flex/aspen-flex-on-demand.gtfs.zip | Bin 9922 -> 0 bytes .../flex/aspen-flex-on-demand.gtfs/agency.txt | 2 + .../booking_rules.txt | 2 + .../aspen-flex-on-demand.gtfs/calendar.txt | 3 + .../calendar_attributes.txt | 22 + .../calendar_dates.txt | 1 + .../aspen-flex-on-demand.gtfs/feed_info.txt | 2 + .../location_groups.txt | 1 + .../locations.geojson | 469 + .../flex/aspen-flex-on-demand.gtfs/routes.txt | 2 + .../flex/aspen-flex-on-demand.gtfs/shapes.txt | 1 + .../aspen-flex-on-demand.gtfs/stop_times.txt | 3 + .../flex/aspen-flex-on-demand.gtfs/stops.txt | 210 + .../flex/aspen-flex-on-demand.gtfs/trips.txt | 3 + .../cobblinc-scheduled-deviated-flex.gtfs.zip | Bin 16553 -> 0 bytes .../agency.txt | 2 + .../booking_rules.txt | 2 + .../calendar.txt | 2 + .../fare_attributes.txt | 2 + .../fare_rules.txt | 10 + .../feed_info.txt | 2 + .../location_groups.txt | 1 + .../locations.geojson | 597 + .../routes.txt | 4 + .../shapes.txt | 351 + .../stop_times.txt | 289 + .../stops.txt | 5 + .../trips.txt | 73 + .../flex/lincoln-county-flex.gtfs.zip | Bin 461815 -> 0 bytes .../flex/lincoln-county-flex.gtfs/agency.txt | 2 + .../flex/lincoln-county-flex.gtfs/areas.txt | 1 + .../booking_rules.txt | 7 + .../lincoln-county-flex.gtfs/calendar.txt | 4 + .../calendar_attributes.txt | 4 + .../calendar_dates.txt | 14 + .../lincoln-county-flex.gtfs/directions.txt | 11 + .../lincoln-county-flex.gtfs/feed_info.txt | 2 + .../locations.geojson | 93139 ++++++++++++++++ .../flex/lincoln-county-flex.gtfs/routes.txt | 7 + .../lincoln-county-flex.gtfs/stop_times.txt | 1023 + .../flex/lincoln-county-flex.gtfs/stops.txt | 17 + .../flex/lincoln-county-flex.gtfs/trips.txt | 57 + 44 files changed, 96353 insertions(+), 4 deletions(-) delete mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs.zip create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/agency.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/booking_rules.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/calendar.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/calendar_attributes.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/calendar_dates.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/feed_info.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/location_groups.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/locations.geojson create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/routes.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/shapes.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/stop_times.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/stops.txt create mode 100644 src/ext-test/resources/flex/aspen-flex-on-demand.gtfs/trips.txt delete mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs.zip create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/agency.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/booking_rules.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/calendar.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_attributes.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_rules.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/feed_info.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/location_groups.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/locations.geojson create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/routes.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/shapes.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stop_times.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stops.txt create mode 100644 src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/trips.txt delete mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs.zip create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/agency.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/areas.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/booking_rules.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/calendar.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/calendar_attributes.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/calendar_dates.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/directions.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/feed_info.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/locations.geojson create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/routes.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/stop_times.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/stops.txt create mode 100644 src/ext-test/resources/flex/lincoln-county-flex.gtfs/trips.txt diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/FlexTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/FlexTest.java index f2cb72ed3da..117da781b4a 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/FlexTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/FlexTest.java @@ -23,11 +23,11 @@ public abstract class FlexTest { - protected static final String ASPEN_GTFS = "/flex/aspen-flex-on-demand.gtfs.zip"; - protected static final String COBB_FLEX_GTFS = "/flex/cobblinc-scheduled-deviated-flex.gtfs.zip"; + protected static final String ASPEN_GTFS = "/flex/aspen-flex-on-demand.gtfs"; + protected static final String COBB_FLEX_GTFS = "/flex/cobblinc-scheduled-deviated-flex.gtfs"; protected static final String COBB_BUS_30_GTFS = "/flex/cobblinc-bus-30-only.gtfs.zip"; protected static final String MARTA_BUS_856_GTFS = "/flex/marta-bus-856-only.gtfs.zip"; - protected static final String LINCOLN_COUNTY_GBFS = "/flex/lincoln-county-flex.gtfs.zip"; + protected static final String LINCOLN_COUNTY_GTFS = "/flex/lincoln-county-flex.gtfs"; protected static final String COBB_OSM = "/flex/cobb-county.filtered.osm.pbf"; protected static final DirectFlexPathCalculator calculator = new DirectFlexPathCalculator(); diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java index 3fb77a29adf..13e88f86c83 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java @@ -223,7 +223,7 @@ void shouldNotInterpolateFlexTimes() { */ @Test void parseContinuousPickup() { - var lincolnGraph = FlexTest.buildFlexGraph(LINCOLN_COUNTY_GBFS); + var lincolnGraph = FlexTest.buildFlexGraph(LINCOLN_COUNTY_GTFS); assertNotNull(lincolnGraph); } diff --git a/src/ext-test/resources/flex/aspen-flex-on-demand.gtfs.zip b/src/ext-test/resources/flex/aspen-flex-on-demand.gtfs.zip deleted file mode 100644 index 2f5d4d32e613dc57837f569450c7d5b72183be57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9922 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 diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/agency.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/agency.txt new file mode 100644 index 00000000000..30325a16880 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/agency.txt @@ -0,0 +1,2 @@ +agency_id,agency_name,agency_url,agency_timezone,agency_lang,agency_phone,agency_branding_url,agency_fare_url,agency_email +1,Cobblinc,https://www.cobbcounty.org/transportation/cobblinc,America/New_York,en,,,, diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/booking_rules.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/booking_rules.txt new file mode 100644 index 00000000000..541e13197c2 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/booking_rules.txt @@ -0,0 +1,2 @@ +booking_rule_id,booking_type,prior_notice_duration_min,prior_notice_duration_max,prior_notice_start_day,prior_notice_start_time,prior_notice_last_day,prior_notice_last_time,prior_notice_service_id,message,pickup_message,drop_off_message,phone_number,info_url,booking_url +1,1,120,1440,,,,,,Call reservationist to schedule.,,,(770) 528-1053,, diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/calendar.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/calendar.txt new file mode 100644 index 00000000000..d055defc895 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/calendar.txt @@ -0,0 +1,2 @@ +service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date +1,1,1,1,1,1,0,0,20211019,20220119 diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_attributes.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_attributes.txt new file mode 100644 index 00000000000..3ebb041bcb3 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_attributes.txt @@ -0,0 +1,2 @@ +fare_id,price,currency_type,payment_method,transfers,agency_id,transfer_duration +flex-adult,2.50,USD,0,0,1, diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_rules.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_rules.txt new file mode 100644 index 00000000000..62e8c4f518f --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/fare_rules.txt @@ -0,0 +1,10 @@ +fare_id,route_id,origin_id,destination_id,contains_id +flex-adult,,Z4,Z3, +flex-adult,,Z3,Z4, +flex-adult,,Z3,Z3, +flex-adult,,Z4,Z2, +flex-adult,,Z2,Z4, +flex-adult,,Z2,Z2, +flex-adult,,Z4,Z1, +flex-adult,,Z1,Z4, +flex-adult,,Z1,Z1, diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/feed_info.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/feed_info.txt new file mode 100644 index 00000000000..0ec181c3a8e --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/feed_info.txt @@ -0,0 +1,2 @@ +feed_publisher_name,feed_id,feed_publisher_url,feed_lang,feed_start_date,feed_end_date,feed_version,default_lang,feed_contact_email,feed_contact_url +Cobblinc,,https://www.cobbcounty.org/transportation/cobblinc,en,20211018,20211111,,,, diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/location_groups.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/location_groups.txt new file mode 100644 index 00000000000..45845294fa8 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/location_groups.txt @@ -0,0 +1 @@ +location_group_id,location_id,location_group_name diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/locations.geojson b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/locations.geojson new file mode 100644 index 00000000000..3f2f8665c30 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/locations.geojson @@ -0,0 +1,597 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "id": "zone_1", + "type": "Feature", + "properties": { + "stop_name": "Flex Zone 1", + "stop_desc": "PUBLIX to Route 30 Transfer Points", + "zone_id": "Z1" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -84.70458984375, + 33.867796513389074 + ], + [ + -84.69547033309937, + 33.8646963242773 + ], + [ + -84.68733787536621, + 33.86157820443925 + ], + [ + -84.68567490577698, + 33.85978746128715 + ], + [ + -84.68505263328552, + 33.85972509642107 + ], + [ + -84.6845269203186, + 33.859600366552314 + ], + [ + -84.68194127082825, + 33.859502364384745 + ], + [ + -84.67999935150146, + 33.85926181313301 + ], + [ + -84.67733860015869, + 33.858762889858156 + ], + [ + -84.67227458953857, + 33.85890543966268 + ], + [ + -84.67103004455566, + 33.858941077076636 + ], + [ + -84.66673851013184, + 33.860722928812585 + ], + [ + -84.66090202331543, + 33.85990328163186 + ], + [ + -84.65712547302246, + 33.85972509642107 + ], + [ + -84.65373516082764, + 33.859760733492976 + ], + [ + -84.65064525604248, + 33.85883416479016 + ], + [ + -84.64862823486327, + 33.8583708766687 + ], + [ + -84.64648246765137, + 33.858620339815644 + ], + [ + -84.64356422424316, + 33.86058038204195 + ], + [ + -84.63223457336426, + 33.86695911708288 + ], + [ + -84.61893081665039, + 33.849175869452154 + ], + [ + -84.61481094360352, + 33.85145689379216 + ], + [ + -84.61360931396484, + 33.85045895313795 + ], + [ + -84.61172103881836, + 33.85145689379216 + ], + [ + -84.61219310760498, + 33.85236572245879 + ], + [ + -84.60996150970459, + 33.85245482278801 + ], + [ + -84.61004734039307, + 33.85311416233549 + ], + [ + -84.60442543029785, + 33.8533101812195 + ], + [ + -84.60004806518555, + 33.85886980223386 + ], + [ + -84.60760116577148, + 33.85986764461944 + ], + [ + -84.60691452026367, + 33.85423680985424 + ], + [ + -84.61309432983397, + 33.85423680985424 + ], + [ + -84.6152400970459, + 33.85566237273956 + ], + [ + -84.62450981140137, + 33.86556937742616 + ], + [ + -84.62665557861328, + 33.86628206725556 + ], + [ + -84.63197708129883, + 33.86806376580027 + ], + [ + -84.63343620300293, + 33.869132767078476 + ], + [ + -84.63480949401854, + 33.87112820031405 + ], + [ + -84.64622497558594, + 33.876187839766146 + ], + [ + -84.65120315551758, + 33.8767579211837 + ], + [ + -84.69695091247557, + 33.876187839766146 + ], + [ + -84.69695091247557, + 33.867493626311635 + ], + [ + -84.6994400024414, + 33.868491367917954 + ], + [ + -84.70407485961914, + 33.869702895619845 + ], + [ + -84.70458984375, + 33.867796513389074 + ] + ] + ] + } + }, + { + "id": "zone_2", + "type": "Feature", + "properties": { + "stop_name": "Flex Zone 2", + "stop_desc": "Horseshoe Bend Plaza to Route 30 Transfer Point", + "zone_id": "Z2" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -84.63489532470703, + 33.87198337170695 + ], + [ + -84.6346378326416, + 33.871146016472125 + ], + [ + -84.63341474533081, + 33.869204033354386 + ], + [ + -84.63199853897095, + 33.86817957491865 + ], + [ + -84.63159084320068, + 33.86797468175618 + ], + [ + -84.62459564208984, + 33.86599699203773 + ], + [ + -84.61957454681396, + 33.86063383710883 + ], + [ + -84.61506843566893, + 33.855680192125064 + ], + [ + -84.61308360099792, + 33.8542991787282 + ], + [ + -84.60694670677185, + 33.854263539377236 + ], + [ + -84.60761189460754, + 33.859885463127526 + ], + [ + -84.60001587867737, + 33.85888762095013 + ], + [ + -84.59524154663086, + 33.864143979919355 + ], + [ + -84.60494041442871, + 33.87419252481561 + ], + [ + -84.6045970916748, + 33.88024958676915 + ], + [ + -84.60253715515137, + 33.88195973819444 + ], + [ + -84.59258079528809, + 33.88509492678373 + ], + [ + -84.58974838256835, + 33.888871250976955 + ], + [ + -84.58356857299805, + 33.895283493992615 + ], + [ + -84.5854139328003, + 33.89563971558044 + ], + [ + -84.59129333496094, + 33.89649464132018 + ], + [ + -84.593825340271, + 33.902265165877225 + ], + [ + -84.59554195404053, + 33.907696938616645 + ], + [ + -84.59605693817139, + 33.908462701690695 + ], + [ + -84.59650754928589, + 33.909549004947415 + ], + [ + -84.59644317626953, + 33.91116952997516 + ], + [ + -84.59884643554688, + 33.90988735887179 + ], + [ + -84.60433959960938, + 33.905755787445045 + ], + [ + -84.60850238800047, + 33.9048297181011 + ], + [ + -84.61399555206299, + 33.90368992663683 + ], + [ + -84.62034702301024, + 33.902585739124085 + ], + [ + -84.62815761566162, + 33.899771777255694 + ], + [ + -84.62824344635008, + 33.89841819289737 + ], + [ + -84.62893009185791, + 33.897420801199644 + ], + [ + -84.63056087493896, + 33.89613842330356 + ], + [ + -84.63219165802, + 33.893644855523824 + ], + [ + -84.63532447814941, + 33.89182806737398 + ], + [ + -84.63708400726318, + 33.89068810210888 + ], + [ + -84.63759899139404, + 33.88940562297412 + ], + [ + -84.63734149932861, + 33.88548681725667 + ], + [ + -84.6369981765747, + 33.881817226884806 + ], + [ + -84.63489532470703, + 33.87198337170695 + ] + ] + ] + } + }, + { + "id": "zone_3", + "type": "Feature", + "properties": { + "stop_name": "Flex Zone 3", + "stop_desc": "Downtown Austell to Route 30 Transfer Point", + "zone_id": "Z3" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -84.60438251495361, + 33.85341710042116 + ], + [ + -84.60449516773222, + 33.8533101812195 + ], + [ + -84.61005806922913, + 33.85311416233549 + ], + [ + -84.60994005203247, + 33.85244591275925 + ], + [ + -84.61217164993286, + 33.85235681242077 + ], + [ + -84.6117103099823, + 33.85143907352557 + ], + [ + -84.61360931396484, + 33.85045895313795 + ], + [ + -84.61481094360352, + 33.851447983659334 + ], + [ + -84.61609840393066, + 33.85074408022878 + ], + [ + -84.62133407592772, + 33.84575421874202 + ], + [ + -84.62442398071289, + 33.84603936153525 + ], + [ + -84.62167739868163, + 33.83919567185717 + ], + [ + -84.62356567382812, + 33.83919567185717 + ], + [ + -84.62871551513672, + 33.838910506226014 + ], + [ + -84.63489532470703, + 33.8397660002649 + ], + [ + -84.63815689086914, + 33.838910506226014 + ], + [ + -84.6470832824707, + 33.84033632486645 + ], + [ + -84.65841293334961, + 33.83933825431594 + ], + [ + -84.65309143066406, + 33.83363477042082 + ], + [ + -84.64828491210936, + 33.831923651036924 + ], + [ + -84.64279174804688, + 33.82636227649246 + ], + [ + -84.6554946899414, + 33.817769954707906 + ], + [ + -84.65510845184326, + 33.81054959781494 + ], + [ + -84.65390682220458, + 33.809515521507386 + ], + [ + -84.65309143066406, + 33.80632406926795 + ], + [ + -84.62339401245117, + 33.8085349203599 + ], + [ + -84.62094783782959, + 33.81388351734996 + ], + [ + -84.61901664733885, + 33.81388351734996 + ], + [ + -84.61785793304443, + 33.81673596567925 + ], + [ + -84.62090492248535, + 33.81577327500237 + ], + [ + -84.62236404418945, + 33.826825738188624 + ], + [ + -84.62116241455078, + 33.82839435913459 + ], + [ + -84.6163558959961, + 33.82850130951472 + ], + [ + -84.61622714996338, + 33.82946385691532 + ], + [ + -84.61747169494629, + 33.83003425026114 + ], + [ + -84.61785793304443, + 33.83302875288965 + ], + [ + -84.61395263671875, + 33.83641526636492 + ], + [ + -84.61326599121094, + 33.84144131795057 + ], + [ + -84.61678504943848, + 33.84144131795057 + ], + [ + -84.61657047271729, + 33.84646707394075 + ], + [ + -84.61489677429199, + 33.847785840378656 + ], + [ + -84.61416721343994, + 33.84757198774456 + ], + [ + -84.6126651763916, + 33.84896202029756 + ], + [ + -84.61142063140869, + 33.84896202029756 + ], + [ + -84.61103439331055, + 33.847001711436604 + ], + [ + -84.61004734039307, + 33.846787856839725 + ], + [ + -84.60944652557373, + 33.84881945389713 + ], + [ + -84.60803031921387, + 33.848926378719746 + ], + [ + -84.60438251495361, + 33.85341710042116 + ] + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/routes.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/routes.txt new file mode 100644 index 00000000000..4e488ca9422 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/routes.txt @@ -0,0 +1,4 @@ +route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_branding_url,route_color,route_text_color,route_sort_order,continuous_pickup,continuous_drop_off +090z,1,Zone 1,PUBLIX Super Market,,3,,,7eafd7,FFFFFF,,2,2 +aamr,1,Zone 2,Horseshoe Bend Pizza,,3,,,a9ca95,FFFFFF,,2,2 +po0p,1,Zone 3,Downtown Austell,,3,,,e18160,FFFFFF,,2,2 diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/shapes.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/shapes.txt new file mode 100644 index 00000000000..d2edbc6290a --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/shapes.txt @@ -0,0 +1,351 @@ +shape_id,shape_pt_sequence,shape_pt_lat,shape_pt_lon,shape_dist_traveled +1603,0,33.864160,-84.674340,0 +1603,1,33.864310,-84.674750,41.3676553616532772 +1603,2,33.864450,-84.675240,89.2135886238208826 +1603,3,33.864470,-84.675420,105.981431995762449 +1603,4,33.864460,-84.675670,129.091131151471473 +1603,5,33.862850,-84.675710,308.153303093688692 +1603,6,33.861310,-84.670790,793.64064397774564 +1603,7,33.861230,-84.670500,821.856781782056942 +1603,8,33.861050,-84.669670,901.065599474204191 +1603,9,33.860970,-84.669210,944.46144211700198 +1603,10,33.860430,-84.665250,1315.00860103015407 +1603,11,33.860450,-84.665020,1336.36202220561586 +1603,12,33.859770,-84.660040,1802.37267252520996 +1603,13,33.859680,-84.659240,1876.91696686866931 +1603,14,33.859650,-84.658580,1937.95056407665402 +1603,15,33.859750,-84.654950,2273.31783540791594 +1603,16,33.859720,-84.654320,2331.5856147646009 +1603,17,33.859690,-84.654020,2359.48681178299285 +1603,18,33.859610,-84.653630,2396.58065355784629 +1603,19,33.859440,-84.652960,2461.26999921240213 +1603,20,33.858670,-84.650340,2717.89864844431168 +1603,21,33.858500,-84.649620,2787.01720676967261 +1603,22,33.858440,-84.649220,2824.55021752373341 +1603,23,33.858420,-84.648570,2884.61126988275237 +1603,24,33.858470,-84.648020,2935.70071922413217 +1603,25,33.858510,-84.647780,2958.30382108636786 +1603,26,33.858640,-84.647270,3007.56490521255773 +1603,27,33.858820,-84.646790,3056.19681660850665 +1603,28,33.859040,-84.646360,3102.83305365301112 +1603,29,33.867630,-84.631050,4808.89751699588669 +1603,30,33.867510,-84.630680,4845.57250132258559 +1603,31,33.867050,-84.629100,5000.15927979081607 +1603,32,33.866740,-84.628070,5101.31276957639147 +1603,33,33.866350,-84.626740,5231.54339896257443 +1603,34,33.865890,-84.625110,5390.49585608849611 +1603,35,33.865740,-84.624700,5431.86287035937767 +1603,36,33.865580,-84.624380,5466.35167998693578 +1603,37,33.865410,-84.624090,5499.12784904032833 +1603,38,33.865220,-84.623820,5531.80542258516834 +1603,39,33.864990,-84.623550,5567.52023576729516 +1603,40,33.864170,-84.622780,5683.14174282334079 +1603,41,33.855180,-84.614540,6939.40195187243262 +1603,42,33.854810,-84.614140,6994.69214287862087 +1603,43,33.854740,-84.614050,7006.07874325375178 +1603,44,33.854590,-84.613820,7033.08395833279792 +1603,45,33.854400,-84.613450,7073.2550700937345 +1603,46,33.854240,-84.613020,7116.76600806439819 +1603,47,33.854170,-84.612800,7138.52150453755439 +1603,48,33.854090,-84.612430,7173.82741232934131 +1603,49,33.854050,-84.612140,7200.97372852915487 +1603,50,33.854030,-84.611080,7298.88257001024522 +1603,51,33.853990,-84.608370,7549.1717147238478 +1603,52,33.853980,-84.606030,7765.25733788839898 +1603,53,33.854000,-84.602300,8109.70411364922438 +1603,54,33.854070,-84.601760,8160.17317170635761 +1603,55,33.854170,-84.601290,8204.97612933502569 +1603,56,33.854690,-84.599810,8353.37152312560647 +1603,57,33.854800,-84.599870,8366.79933403518226 +1603,58,33.854620,-84.600380,8417.97063950866686 +5mw2,0,33.883310,-84.620270,0 +5mw2,1,33.883100,-84.620380,25.4632412848342753 +5mw2,2,33.882770,-84.619380,124.800729087131458 +5mw2,3,33.881920,-84.619930,232.090136550085901 +5mw2,4,33.878200,-84.622150,693.720674651098534 +5mw2,5,33.875140,-84.623950,1072.38724479474945 +5mw2,6,33.874410,-84.624310,1160.1001415742428 +5mw2,7,33.873860,-84.624640,1228.42578060626147 +5mw2,8,33.873140,-84.625040,1316.59273529802135 +5mw2,9,33.873010,-84.625140,1333.74475359342864 +5mw2,10,33.872650,-84.625320,1377.08734117159929 +5mw2,11,33.871900,-84.625800,1471.52663025872175 +5mw2,12,33.871020,-84.626500,1588.79379329057519 +5mw2,13,33.870240,-84.627250,1699.77654563159331 +5mw2,14,33.869520,-84.628020,1806.84472985877164 +5mw2,15,33.868520,-84.629500,1983.01464183445728 +5mw2,16,33.867990,-84.630390,2084.13494192404596 +5mw2,17,33.867630,-84.631050,2157.04367103032746 +5mw2,18,33.867510,-84.630680,2193.71865535702636 +5mw2,19,33.867050,-84.629100,2348.30543382525684 +5mw2,20,33.866740,-84.628070,2449.4589236108327 +5mw2,21,33.866350,-84.626740,2579.68955299701611 +5mw2,22,33.865890,-84.625110,2738.64201012293779 +5mw2,23,33.865740,-84.624700,2780.00902439381935 +5mw2,24,33.865580,-84.624380,2814.497834021377 +5mw2,25,33.865410,-84.624090,2847.2740030747691 +5mw2,26,33.865220,-84.623820,2879.95157661960911 +5mw2,27,33.864990,-84.623550,2915.66638980173593 +5mw2,28,33.864170,-84.622780,3031.28789685778111 +5mw2,29,33.855180,-84.614540,4287.54810590687339 +5mw2,30,33.854810,-84.614140,4342.83829691306164 +5mw2,31,33.854740,-84.614050,4354.22489728819255 +5mw2,32,33.854590,-84.613820,4381.23011236723869 +5mw2,33,33.854400,-84.613450,4421.40122412817527 +5mw2,34,33.854240,-84.613020,4464.91216209883896 +5mw2,35,33.854170,-84.612800,4486.66765857199516 +5mw2,36,33.854090,-84.612430,4521.97356636378208 +5mw2,37,33.854050,-84.612140,4549.11988256359564 +5mw2,38,33.854030,-84.611080,4647.02872404468599 +5mw2,39,33.853990,-84.608370,4897.31786875828857 +5mw2,40,33.853980,-84.606030,5113.40349192283975 +5mw2,41,33.854000,-84.602300,5457.85026768366515 +5mw2,42,33.854070,-84.601760,5508.31932574079838 +5mw2,43,33.854170,-84.601290,5553.12228336946646 +5mw2,44,33.854690,-84.599810,5701.51767716004724 +5mw2,45,33.854800,-84.599870,5714.94548806962302 +5mw2,46,33.854620,-84.600380,5766.11679354310763 +cizy,0,33.854620,-84.600380,0 +cizy,1,33.854800,-84.599870,51.1713054734841535 +cizy,2,33.854690,-84.599810,64.5991163830600641 +cizy,3,33.854170,-84.601290,212.99451017364089 +cizy,4,33.854070,-84.601760,257.797467802309143 +cizy,5,33.854000,-84.602300,308.266525859442254 +cizy,6,33.853980,-84.606030,652.713301620267202 +cizy,7,33.853990,-84.608370,868.798924784818155 +cizy,8,33.854030,-84.611080,1119.08806949842074 +cizy,9,33.854050,-84.612140,1216.99691097951154 +cizy,10,33.854090,-84.612430,1244.14322717932464 +cizy,11,33.854170,-84.612800,1279.44913497111179 +cizy,12,33.854240,-84.613020,1301.20463144426776 +cizy,13,33.854400,-84.613450,1344.715569414931 +cizy,14,33.854590,-84.613820,1384.88668117586758 +cizy,15,33.854740,-84.614050,1411.89189625491349 +cizy,16,33.854810,-84.614140,1423.27849663004486 +cizy,17,33.855180,-84.614540,1478.56868763623311 +cizy,18,33.864170,-84.622780,2734.82889668532516 +cizy,19,33.864990,-84.623550,2850.45040374137034 +cizy,20,33.865220,-84.623820,2886.16521692349716 +cizy,21,33.865410,-84.624090,2918.84279046833717 +cizy,22,33.865580,-84.624380,2951.61895952172927 +cizy,23,33.865740,-84.624700,2986.10776914928692 +cizy,24,33.865890,-84.625110,3027.47478342016848 +cizy,25,33.866350,-84.626740,3186.42724054609016 +cizy,26,33.866740,-84.628070,3316.65786993227357 +cizy,27,33.867050,-84.629100,3417.81135971784943 +cizy,28,33.867510,-84.630680,3572.3981381860799 +cizy,29,33.867630,-84.631050,3609.07312251277881 +cizy,30,33.859040,-84.646360,5315.13758585565392 +cizy,31,33.858820,-84.646790,5361.77382290015794 +cizy,32,33.858640,-84.647270,5410.40573429610686 +cizy,33,33.858510,-84.647780,5459.66681842229718 +cizy,34,33.858470,-84.648020,5482.26992028453242 +cizy,35,33.858420,-84.648570,5533.35936962591222 +cizy,36,33.858440,-84.649220,5593.42042198493164 +cizy,37,33.858500,-84.649620,5630.95343273899198 +cizy,38,33.858670,-84.650340,5700.07199106435291 +cizy,39,33.859440,-84.652960,5956.70064029626246 +cizy,40,33.859610,-84.653630,6021.3899859508183 +cizy,41,33.859690,-84.654020,6058.48382772567129 +cizy,42,33.859720,-84.654320,6086.38502474406323 +cizy,43,33.859750,-84.654950,6144.65280410074774 +cizy,44,33.859650,-84.658580,6480.02007543200943 +cizy,45,33.859680,-84.659240,6541.05367263999415 +cizy,46,33.859770,-84.660040,6615.59796698345326 +cizy,47,33.860450,-84.665020,7081.60861730304714 +cizy,48,33.860430,-84.665250,7102.96203847850938 +cizy,49,33.860970,-84.669210,7473.50919739166147 +cizy,50,33.861050,-84.669670,7516.90504003445949 +cizy,51,33.861230,-84.670500,7596.11385772660651 +cizy,52,33.861310,-84.670790,7624.32999553091759 +cizy,53,33.862850,-84.675710,8109.81733641497431 +cizy,54,33.864460,-84.675670,8288.8795083571913 +cizy,55,33.864470,-84.675420,8311.98920751290098 +cizy,56,33.864450,-84.675240,8328.7570508848421 +cizy,57,33.864310,-84.674750,8376.60298414700992 +cizy,58,33.864160,-84.674340,8417.97063950866323 +fj8w,0,33.812130,-84.634480,0 +fj8w,1,33.812170,-84.634360,11.9455210030212005 +fj8w,2,33.812710,-84.634610,76.279913916894813 +fj8w,3,33.812850,-84.634650,92.279849053187931 +fj8w,4,33.813260,-84.633250,229.421571582750914 +fj8w,5,33.813330,-84.632900,262.680664666869916 +fj8w,6,33.813470,-84.631130,426.94482553777982 +fj8w,7,33.813580,-84.629890,542.155555480363091 +fj8w,8,33.813700,-84.629120,614.533884663003732 +fj8w,9,33.813850,-84.628330,689.400820648105878 +fj8w,10,33.814020,-84.627630,756.777336790232653 +fj8w,11,33.815340,-84.622650,1239.70300436535308 +fj8w,12,33.816710,-84.617700,1721.71029261900571 +fj8w,13,33.816980,-84.616660,1822.37033079301045 +fj8w,14,33.816830,-84.616620,1839.45404263526211 +fj8w,15,33.816640,-84.616600,1860.66174775616264 +fj8w,16,33.816430,-84.616610,1884.0309823274722 +fj8w,17,33.816150,-84.616680,1915.83011858231112 +fj8w,18,33.816000,-84.616780,1934.89699733012708 +fj8w,19,33.815840,-84.616960,1959.24973939017377 +fj8w,20,33.815700,-84.617250,1990.23560192697937 +fj8w,21,33.815660,-84.617460,2010.13965870778543 +fj8w,22,33.815650,-84.617750,2036.95422308684397 +fj8w,23,33.815680,-84.617870,2048.53136993844828 +fj8w,24,33.815730,-84.617940,2057.05966327484066 +fj8w,25,33.815830,-84.618000,2069.48419467573149 +fj8w,26,33.815900,-84.618010,2077.32248401577999 +fj8w,27,33.816590,-84.617830,2155.82848224535564 +fj8w,28,33.817020,-84.617780,2203.86497053938547 +fj8w,29,33.817450,-84.617790,2251.68777899641691 +fj8w,30,33.818280,-84.617920,2344.75780688978466 +fj8w,31,33.818580,-84.617950,2378.23125954415173 +fj8w,32,33.818970,-84.617960,2421.60717951736524 +fj8w,33,33.819610,-84.617940,2492.79601104468929 +fj8w,34,33.820250,-84.617840,2564.55795400538045 +fj8w,35,33.820570,-84.617740,2601.32000575365601 +fj8w,36,33.821140,-84.617530,2667.60363081003698 +fj8w,37,33.822000,-84.617110,2770.80255010889414 +fj8w,38,33.822450,-84.616910,2824.14224711326233 +fj8w,39,33.824120,-84.616290,3018.46968055592561 +fj8w,40,33.824610,-84.616070,3076.62192977544873 +fj8w,41,33.825150,-84.615800,3141.64117829165889 +fj8w,42,33.829950,-84.613300,3723.19321138423675 +fj8w,43,33.830700,-84.612930,3813.3207347007874 +fj8w,44,33.832430,-84.612080,4021.09324516900551 +fj8w,45,33.833230,-84.611770,4114.5440614867648 +fj8w,46,33.833860,-84.611600,4186.33517561256576 +fj8w,47,33.834760,-84.611440,4287.49602809629869 +fj8w,48,33.837440,-84.611330,4585.67198383807136 +fj8w,49,33.838680,-84.611160,4724.4449904067551 +fj8w,50,33.839410,-84.610990,4807.12197254783678 +fj8w,51,33.843350,-84.609680,5261.6294821976544 +fj8w,52,33.843890,-84.609530,5323.25214634696658 +fj8w,53,33.844970,-84.609300,5445.20691247350896 +fj8w,54,33.846290,-84.609110,5593.02954218924333 +fj8w,55,33.846600,-84.609050,5627.9425358250528 +fj8w,56,33.847280,-84.608850,5705.77838507436354 +fj8w,57,33.847640,-84.608680,5748.77715408244603 +fj8w,58,33.848230,-84.608340,5821.50897298361815 +fj8w,59,33.848860,-84.607870,5903.91841611216842 +fj8w,60,33.851630,-84.605380,6288.29422883609277 +fj8w,61,33.852830,-84.604320,6453.78217286460767 +fj8w,62,33.853990,-84.603350,6610.81991596658008 +fj8w,63,33.854000,-84.602300,6707.78649418878922 +fj8w,64,33.854070,-84.601760,6758.25555224592244 +fj8w,65,33.854170,-84.601290,6803.05850987459053 +fj8w,66,33.854690,-84.599810,6951.45390366517131 +fj8w,67,33.854800,-84.599870,6964.88171457474709 +fj8w,68,33.854620,-84.600380,7016.0530200482317 +swh2,0,33.854620,-84.600380,0 +swh2,1,33.854800,-84.599870,51.1713054734841535 +swh2,2,33.854690,-84.599810,64.5991163830600641 +swh2,3,33.854170,-84.601290,212.99451017364089 +swh2,4,33.854070,-84.601760,257.797467802309143 +swh2,5,33.854000,-84.602300,308.266525859442254 +swh2,6,33.853990,-84.603350,405.233104081651106 +swh2,7,33.852830,-84.604320,562.270847183623459 +swh2,8,33.851630,-84.605380,727.758791212138476 +swh2,9,33.848860,-84.607870,1112.1346039360626 +swh2,10,33.848230,-84.608340,1194.54404706461241 +swh2,11,33.847640,-84.608680,1267.27586596578431 +swh2,12,33.847280,-84.608850,1310.27463497386657 +swh2,13,33.846600,-84.609050,1388.11048422317776 +swh2,14,33.846290,-84.609110,1423.02347785898746 +swh2,15,33.844970,-84.609300,1570.84610757472137 +swh2,16,33.843890,-84.609530,1692.80087370126375 +swh2,17,33.843350,-84.609680,1754.42353785057549 +swh2,18,33.839410,-84.610990,2208.93104750039311 +swh2,19,33.838680,-84.611160,2291.60802964147479 +swh2,20,33.837440,-84.611330,2430.38103621015898 +swh2,21,33.834760,-84.611440,2728.55699195193165 +swh2,22,33.833860,-84.611600,2829.71784443566457 +swh2,23,33.833230,-84.611770,2901.50895856146553 +swh2,24,33.832430,-84.612080,2994.95977487922482 +swh2,25,33.830700,-84.612930,3202.73228534744294 +swh2,26,33.829950,-84.613300,3292.85980866399359 +swh2,27,33.825150,-84.615800,3874.41184175657145 +swh2,28,33.824610,-84.616070,3939.4310902727816 +swh2,29,33.824120,-84.616290,3997.58333949230473 +swh2,30,33.822450,-84.616910,4191.91077293496801 +swh2,31,33.822000,-84.617110,4245.25046993933665 +swh2,32,33.821140,-84.617530,4348.44938923819336 +swh2,33,33.820570,-84.617740,4414.73301429457388 +swh2,34,33.820250,-84.617840,4451.49506604284943 +swh2,35,33.819610,-84.617940,4523.25700900354059 +swh2,36,33.818970,-84.617960,4594.4458405308651 +swh2,37,33.818580,-84.617950,4637.82176050407907 +swh2,38,33.818280,-84.617920,4671.29521315844613 +swh2,39,33.817450,-84.617790,4764.36524105181434 +swh2,40,33.817020,-84.617780,4812.18804950884532 +swh2,41,33.816590,-84.617830,4860.22453780287469 +swh2,42,33.815900,-84.618010,4938.73053603244989 +swh2,43,33.815830,-84.618000,4946.5688253724984 +swh2,44,33.815730,-84.617940,4958.99335677338877 +swh2,45,33.815680,-84.617870,4967.52165010978115 +swh2,46,33.815650,-84.617750,4979.09879696138523 +swh2,47,33.815660,-84.617460,5005.91336134044377 +swh2,48,33.815700,-84.617250,5025.81741812124983 +swh2,49,33.815840,-84.616960,5056.80328065805497 +swh2,50,33.816000,-84.616780,5081.15602271810167 +swh2,51,33.816150,-84.616680,5100.22290146591786 +swh2,52,33.816430,-84.616610,5132.022037720757 +swh2,53,33.816640,-84.616600,5155.39127229206679 +swh2,54,33.816830,-84.616620,5176.59897741296754 +swh2,55,33.816980,-84.616660,5193.68268925521897 +swh2,56,33.816710,-84.617700,5294.34272742922349 +swh2,57,33.815340,-84.622650,5776.35001568287589 +swh2,58,33.814020,-84.627630,6259.27568325799621 +swh2,59,33.813850,-84.628330,6326.65219940012321 +swh2,60,33.813700,-84.629120,6401.51913538522513 +swh2,61,33.813580,-84.629890,6473.89746456786543 +swh2,62,33.813470,-84.631130,6589.10819451044881 +swh2,63,33.813330,-84.632900,6753.37235538135883 +swh2,64,33.813260,-84.633250,6786.63144846547766 +swh2,65,33.812850,-84.634650,6923.77317099504035 +swh2,66,33.812710,-84.634610,6939.77310613133341 +swh2,67,33.812170,-84.634360,7004.10749904520708 +swh2,68,33.812130,-84.634480,7016.05302004822806 +wm2h,0,33.854620,-84.600380,0 +wm2h,1,33.854800,-84.599870,51.1713054734841535 +wm2h,2,33.854690,-84.599810,64.5991163830600641 +wm2h,3,33.854170,-84.601290,212.99451017364089 +wm2h,4,33.854070,-84.601760,257.797467802309143 +wm2h,5,33.854000,-84.602300,308.266525859442254 +wm2h,6,33.853980,-84.606030,652.713301620267202 +wm2h,7,33.853990,-84.608370,868.798924784818155 +wm2h,8,33.854030,-84.611080,1119.08806949842074 +wm2h,9,33.854050,-84.612140,1216.99691097951154 +wm2h,10,33.854090,-84.612430,1244.14322717932464 +wm2h,11,33.854170,-84.612800,1279.44913497111179 +wm2h,12,33.854240,-84.613020,1301.20463144426776 +wm2h,13,33.854400,-84.613450,1344.715569414931 +wm2h,14,33.854590,-84.613820,1384.88668117586758 +wm2h,15,33.854740,-84.614050,1411.89189625491349 +wm2h,16,33.854810,-84.614140,1423.27849663004486 +wm2h,17,33.855180,-84.614540,1478.56868763623311 +wm2h,18,33.864170,-84.622780,2734.82889668532516 +wm2h,19,33.864990,-84.623550,2850.45040374137034 +wm2h,20,33.865220,-84.623820,2886.16521692349716 +wm2h,21,33.865410,-84.624090,2918.84279046833717 +wm2h,22,33.865580,-84.624380,2951.61895952172927 +wm2h,23,33.865740,-84.624700,2986.10776914928692 +wm2h,24,33.865890,-84.625110,3027.47478342016848 +wm2h,25,33.866350,-84.626740,3186.42724054609016 +wm2h,26,33.866740,-84.628070,3316.65786993227357 +wm2h,27,33.867050,-84.629100,3417.81135971784943 +wm2h,28,33.867510,-84.630680,3572.3981381860799 +wm2h,29,33.867630,-84.631050,3609.07312251277881 +wm2h,30,33.867990,-84.630390,3681.98185161906031 +wm2h,31,33.868520,-84.629500,3783.10215170864876 +wm2h,32,33.869520,-84.628020,3959.27206368433463 +wm2h,33,33.870240,-84.627250,4066.34024791151296 +wm2h,34,33.871020,-84.626500,4177.32300025253153 +wm2h,35,33.871900,-84.625800,4294.5901632843852 +wm2h,36,33.872650,-84.625320,4389.02945237150743 +wm2h,37,33.873010,-84.625140,4432.37203994967786 +wm2h,38,33.873140,-84.625040,4449.52405824508514 +wm2h,39,33.873860,-84.624640,4537.69101293684525 +wm2h,40,33.874410,-84.624310,4606.0166519688637 +wm2h,41,33.875140,-84.623950,4693.72954874835705 +wm2h,42,33.878200,-84.622150,5072.39611889200751 +wm2h,43,33.881920,-84.619930,5534.02665699301997 +wm2h,44,33.882770,-84.619380,5641.31606445597481 +wm2h,45,33.883100,-84.620380,5740.6535522582717 +wm2h,46,33.883310,-84.620270,5766.11679354310581 diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stop_times.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stop_times.txt new file mode 100644 index 00000000000..bfeb52654d8 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stop_times.txt @@ -0,0 +1,289 @@ +trip_id,stop_sequence,stop_id,arrival_time,departure_time,stop_headsign,pickup_type,drop_off_type,continuous_pickup,continuous_drop_off,shape_dist_traveled,timepoint,start_pickup_drop_off_window,end_pickup_drop_off_window,mean_duration_factor,mean_duration_offset,safe_duration_factor,safe_duration_offset,pickup_booking_rule_id,dropoff_booking_rule_id +4d838cf4-d44d-4e08-a364-f22c34a8c89e,0,yz85,7:30:00,7:30:00,,,,,,,0,,,,,,,, +4d838cf4-d44d-4e08-a364-f22c34a8c89e,1,zone_1,,,,2,2,,,,0,7:30:00,8:00:00,,,,,1,1 +4d838cf4-d44d-4e08-a364-f22c34a8c89e,2,zone_1,,,,2,2,,,,0,7:30:00,8:00:00,,,,,1,1 +4d838cf4-d44d-4e08-a364-f22c34a8c89e,3,cujv,8:00:00,8:00:00,,,,,,,0,,,,,,,, +48071338-a326-4da6-aca6-b1e0de935e5e,0,yz85,8:30:00,8:30:00,,,,,,,0,,,,,,,, +48071338-a326-4da6-aca6-b1e0de935e5e,1,zone_1,,,,2,2,,,,0,8:30:00,9:00:00,,,,,1,1 +48071338-a326-4da6-aca6-b1e0de935e5e,2,zone_1,,,,2,2,,,,0,8:30:00,9:00:00,,,,,1,1 +48071338-a326-4da6-aca6-b1e0de935e5e,3,cujv,9:00:00,9:00:00,,,,,,,0,,,,,,,, +3a4c1a1e-bbfd-46cc-8b2c-f68c7b0dca7c,0,yz85,10:30:00,10:30:00,,,,,,,0,,,,,,,, +3a4c1a1e-bbfd-46cc-8b2c-f68c7b0dca7c,1,zone_1,,,,2,2,,,,0,10:30:00,11:00:00,,,,,1,1 +3a4c1a1e-bbfd-46cc-8b2c-f68c7b0dca7c,2,zone_1,,,,2,2,,,,0,10:30:00,11:00:00,,,,,1,1 +3a4c1a1e-bbfd-46cc-8b2c-f68c7b0dca7c,3,cujv,11:00:00,11:00:00,,,,,,,0,,,,,,,, +55db7288-4c30-47ba-b766-16a09b1d5020,0,yz85,9:30:00,9:30:00,,,,,,,0,,,,,,,, +55db7288-4c30-47ba-b766-16a09b1d5020,1,zone_1,,,,2,2,,,,0,9:30:00,10:00:00,,,,,1,1 +55db7288-4c30-47ba-b766-16a09b1d5020,2,zone_1,,,,2,2,,,,0,9:30:00,10:00:00,,,,,1,1 +55db7288-4c30-47ba-b766-16a09b1d5020,3,cujv,10:00:00,10:00:00,,,,,,,0,,,,,,,, +3570424a-a8ae-4a7c-8137-c6f6245ddfca,0,yz85,12:30:00,12:30:00,,,,,,,0,,,,,,,, +3570424a-a8ae-4a7c-8137-c6f6245ddfca,1,zone_1,,,,2,2,,,,0,12:30:00,13:00:00,,,,,1,1 +3570424a-a8ae-4a7c-8137-c6f6245ddfca,2,zone_1,,,,2,2,,,,0,12:30:00,13:00:00,,,,,1,1 +3570424a-a8ae-4a7c-8137-c6f6245ddfca,3,cujv,13:00:00,13:00:00,,,,,,,0,,,,,,,, +d0cc6a8d-78c6-496a-aa3e-66c0829930f1,0,yz85,13:30:00,13:30:00,,,,,,,0,,,,,,,, +d0cc6a8d-78c6-496a-aa3e-66c0829930f1,1,zone_1,,,,2,2,,,,0,13:30:00,14:00:00,,,,,1,1 +d0cc6a8d-78c6-496a-aa3e-66c0829930f1,2,zone_1,,,,2,2,,,,0,13:30:00,14:00:00,,,,,1,1 +d0cc6a8d-78c6-496a-aa3e-66c0829930f1,3,cujv,14:00:00,14:00:00,,,,,,,0,,,,,,,, +50dfb2c0-d8ba-4dc6-a104-a3cc058feae9,0,yz85,11:30:00,11:30:00,,,,,,,0,,,,,,,, +50dfb2c0-d8ba-4dc6-a104-a3cc058feae9,1,zone_1,,,,2,2,,,,0,11:30:00,12:00:00,,,,,1,1 +50dfb2c0-d8ba-4dc6-a104-a3cc058feae9,2,zone_1,,,,2,2,,,,0,11:30:00,12:00:00,,,,,1,1 +50dfb2c0-d8ba-4dc6-a104-a3cc058feae9,3,cujv,12:00:00,12:00:00,,,,,,,0,,,,,,,, +1d32fa36-c9db-4ca2-a26b-574935e99081,0,yz85,15:30:00,15:30:00,,,,,,,0,,,,,,,, +1d32fa36-c9db-4ca2-a26b-574935e99081,1,zone_1,,,,2,2,,,,0,15:30:00,16:00:00,,,,,1,1 +1d32fa36-c9db-4ca2-a26b-574935e99081,2,zone_1,,,,2,2,,,,0,15:30:00,16:00:00,,,,,1,1 +1d32fa36-c9db-4ca2-a26b-574935e99081,3,cujv,16:00:00,16:00:00,,,,,,,0,,,,,,,, +273d01f4-1adb-4c9d-9fef-54c861fd15d0,0,yz85,14:30:00,14:30:00,,,,,,,0,,,,,,,, +273d01f4-1adb-4c9d-9fef-54c861fd15d0,1,zone_1,,,,2,2,,,,0,14:30:00,15:00:00,,,,,1,1 +273d01f4-1adb-4c9d-9fef-54c861fd15d0,2,zone_1,,,,2,2,,,,0,14:30:00,15:00:00,,,,,1,1 +273d01f4-1adb-4c9d-9fef-54c861fd15d0,3,cujv,15:00:00,15:00:00,,,,,,,0,,,,,,,, +a642849a-c0e1-4308-b6c4-0ad12c56744c,0,yz85,16:30:00,16:30:00,,,,,,,0,,,,,,,, +a642849a-c0e1-4308-b6c4-0ad12c56744c,1,zone_1,,,,2,2,,,,0,16:30:00,17:00:00,,,,,1,1 +a642849a-c0e1-4308-b6c4-0ad12c56744c,2,zone_1,,,,2,2,,,,0,16:30:00,17:00:00,,,,,1,1 +a642849a-c0e1-4308-b6c4-0ad12c56744c,3,cujv,17:00:00,17:00:00,,,,,,,0,,,,,,,, +adef9bc9-98ee-4ae1-99a9-5b55bb01bf52,0,yz85,17:30:00,17:30:00,,,,,,,0,,,,,,,, +adef9bc9-98ee-4ae1-99a9-5b55bb01bf52,1,zone_1,,,,2,2,,,,0,17:30:00,18:00:00,,,,,1,1 +adef9bc9-98ee-4ae1-99a9-5b55bb01bf52,2,zone_1,,,,2,2,,,,0,17:30:00,18:00:00,,,,,1,1 +adef9bc9-98ee-4ae1-99a9-5b55bb01bf52,3,cujv,18:00:00,18:00:00,,,,,,,0,,,,,,,, +a62fe28a-b95b-4f37-b72c-db27af73e6fe,0,yz85,18:30:00,18:30:00,,,,,,,0,,,,,,,, +a62fe28a-b95b-4f37-b72c-db27af73e6fe,1,zone_1,,,,2,2,,,,0,18:30:00,19:00:00,,,,,1,1 +a62fe28a-b95b-4f37-b72c-db27af73e6fe,2,zone_1,,,,2,2,,,,0,18:30:00,19:00:00,,,,,1,1 +a62fe28a-b95b-4f37-b72c-db27af73e6fe,3,cujv,19:00:00,19:00:00,,,,,,,0,,,,,,,, +b43131c7-63c2-4127-a837-6987dcc428ae,0,cujv,7:00:00,7:00:00,,,,,,,0,,,,,,,, +b43131c7-63c2-4127-a837-6987dcc428ae,1,zone_1,,,,2,2,,,,0,7:00:00,7:30:00,,,,,1,1 +b43131c7-63c2-4127-a837-6987dcc428ae,2,zone_1,,,,2,2,,,,0,7:00:00,7:30:00,,,,,1,1 +b43131c7-63c2-4127-a837-6987dcc428ae,3,yz85,7:30:00,7:30:00,,,,,,,0,,,,,,,, +5ad42b7b-30df-47ad-8264-b9c1119d954a,0,cujv,9:00:00,9:00:00,,,,,,,0,,,,,,,, +5ad42b7b-30df-47ad-8264-b9c1119d954a,1,zone_1,,,,2,2,,,,0,9:00:00,9:30:00,,,,,1,1 +5ad42b7b-30df-47ad-8264-b9c1119d954a,2,zone_1,,,,2,2,,,,0,9:00:00,9:30:00,,,,,1,1 +5ad42b7b-30df-47ad-8264-b9c1119d954a,3,yz85,9:30:00,9:30:00,,,,,,,0,,,,,,,, +0ef63de2-f001-423e-b2c8-cb362db810dc,0,cujv,10:00:00,10:00:00,,,,,,,0,,,,,,,, +0ef63de2-f001-423e-b2c8-cb362db810dc,1,zone_1,,,,2,2,,,,0,10:00:00,10:30:00,,,,,1,1 +0ef63de2-f001-423e-b2c8-cb362db810dc,2,zone_1,,,,2,2,,,,0,10:00:00,10:30:00,,,,,1,1 +0ef63de2-f001-423e-b2c8-cb362db810dc,3,yz85,10:30:00,10:30:00,,,,,,,0,,,,,,,, +580c504a-d9e8-446f-8a79-efedbeda8dab,0,cujv,8:00:00,8:00:00,,,,,,,0,,,,,,,, +580c504a-d9e8-446f-8a79-efedbeda8dab,1,zone_1,,,,2,2,,,,0,8:00:00,8:30:00,,,,,1,1 +580c504a-d9e8-446f-8a79-efedbeda8dab,2,zone_1,,,,2,2,,,,0,8:00:00,8:30:00,,,,,1,1 +580c504a-d9e8-446f-8a79-efedbeda8dab,3,yz85,8:30:00,8:30:00,,,,,,,0,,,,,,,, +54c6c881-ec67-4a66-bd9f-3b61c83b326b,0,cujv,11:00:00,11:00:00,,,,,,,0,,,,,,,, +54c6c881-ec67-4a66-bd9f-3b61c83b326b,1,zone_1,,,,2,2,,,,0,11:00:00,11:30:00,,,,,1,1 +54c6c881-ec67-4a66-bd9f-3b61c83b326b,2,zone_1,,,,2,2,,,,0,11:00:00,11:30:00,,,,,1,1 +54c6c881-ec67-4a66-bd9f-3b61c83b326b,3,yz85,11:30:00,11:30:00,,,,,,,0,,,,,,,, +ac07359f-3afa-4de6-a076-d746cbc83ded,0,cujv,13:00:00,13:00:00,,,,,,,0,,,,,,,, +ac07359f-3afa-4de6-a076-d746cbc83ded,1,zone_1,,,,2,2,,,,0,13:00:00,13:30:00,,,,,1,1 +ac07359f-3afa-4de6-a076-d746cbc83ded,2,zone_1,,,,2,2,,,,0,13:00:00,13:30:00,,,,,1,1 +ac07359f-3afa-4de6-a076-d746cbc83ded,3,yz85,13:30:00,13:30:00,,,,,,,0,,,,,,,, +89367b3a-da78-4420-b497-01aa9017068d,0,cujv,12:00:00,12:00:00,,,,,,,0,,,,,,,, +89367b3a-da78-4420-b497-01aa9017068d,1,zone_1,,,,2,2,,,,0,12:00:00,12:30:00,,,,,1,1 +89367b3a-da78-4420-b497-01aa9017068d,2,zone_1,,,,2,2,,,,0,12:00:00,12:30:00,,,,,1,1 +89367b3a-da78-4420-b497-01aa9017068d,3,yz85,12:30:00,12:30:00,,,,,,,0,,,,,,,, +c8bd2ce1-eff7-4504-8fd7-2416de4d9413,0,cujv,14:00:00,14:00:00,,,,,,,0,,,,,,,, +c8bd2ce1-eff7-4504-8fd7-2416de4d9413,1,zone_1,,,,2,2,,,,0,14:00:00,14:30:00,,,,,1,1 +c8bd2ce1-eff7-4504-8fd7-2416de4d9413,2,zone_1,,,,2,2,,,,0,14:00:00,14:30:00,,,,,1,1 +c8bd2ce1-eff7-4504-8fd7-2416de4d9413,3,yz85,14:30:00,14:30:00,,,,,,,0,,,,,,,, +202bd60a-a979-4bba-86b0-d0b1e870bdfc,0,cujv,17:00:00,17:00:00,,,,,,,0,,,,,,,, +202bd60a-a979-4bba-86b0-d0b1e870bdfc,1,zone_1,,,,2,2,,,,0,17:00:00,17:30:00,,,,,1,1 +202bd60a-a979-4bba-86b0-d0b1e870bdfc,2,zone_1,,,,2,2,,,,0,17:00:00,17:30:00,,,,,1,1 +202bd60a-a979-4bba-86b0-d0b1e870bdfc,3,yz85,17:30:00,17:30:00,,,,,,,0,,,,,,,, +6cd8ea48-276d-45d7-852c-167a8f2b13fa,0,cujv,15:00:00,15:00:00,,,,,,,0,,,,,,,, +6cd8ea48-276d-45d7-852c-167a8f2b13fa,1,zone_1,,,,2,2,,,,0,15:00:00,15:30:00,,,,,1,1 +6cd8ea48-276d-45d7-852c-167a8f2b13fa,2,zone_1,,,,2,2,,,,0,15:00:00,15:30:00,,,,,1,1 +6cd8ea48-276d-45d7-852c-167a8f2b13fa,3,yz85,15:30:00,15:30:00,,,,,,,0,,,,,,,, +19290d0c-323c-499b-aa37-65cb80505d6b,0,cujv,16:00:00,16:00:00,,,,,,,0,,,,,,,, +19290d0c-323c-499b-aa37-65cb80505d6b,1,zone_1,,,,2,2,,,,0,16:00:00,16:30:00,,,,,1,1 +19290d0c-323c-499b-aa37-65cb80505d6b,2,zone_1,,,,2,2,,,,0,16:00:00,16:30:00,,,,,1,1 +19290d0c-323c-499b-aa37-65cb80505d6b,3,yz85,16:30:00,16:30:00,,,,,,,0,,,,,,,, +f665bd4d-6f7a-4fbf-97ba-e602c17620c2,0,cujv,18:00:00,18:00:00,,,,,,,0,,,,,,,, +f665bd4d-6f7a-4fbf-97ba-e602c17620c2,1,zone_1,,,,2,2,,,,0,18:00:00,18:30:00,,,,,1,1 +f665bd4d-6f7a-4fbf-97ba-e602c17620c2,2,zone_1,,,,2,2,,,,0,18:00:00,18:30:00,,,,,1,1 +f665bd4d-6f7a-4fbf-97ba-e602c17620c2,3,yz85,18:30:00,18:30:00,,,,,,,0,,,,,,,, +9d80fb21-203f-4e0f-b79c-5d584ebe4ffd,0,7y7t,7:30:00,7:30:00,,,,,,,0,,,,,,,, +9d80fb21-203f-4e0f-b79c-5d584ebe4ffd,1,zone_2,,,,2,2,,,,0,7:30:00,8:00:00,,,,,1,1 +9d80fb21-203f-4e0f-b79c-5d584ebe4ffd,2,zone_2,,,,2,2,,,,0,7:30:00,8:00:00,,,,,1,1 +9d80fb21-203f-4e0f-b79c-5d584ebe4ffd,3,cujv,8:00:00,8:00:00,,,,,,,0,,,,,,,, +679e1454-ae4b-4c5d-a594-78c30b76843e,0,7y7t,8:30:00,8:30:00,,,,,,,0,,,,,,,, +679e1454-ae4b-4c5d-a594-78c30b76843e,1,zone_2,,,,2,2,,,,0,8:30:00,9:00:00,,,,,1,1 +679e1454-ae4b-4c5d-a594-78c30b76843e,2,zone_2,,,,2,2,,,,0,8:30:00,9:00:00,,,,,1,1 +679e1454-ae4b-4c5d-a594-78c30b76843e,3,cujv,9:00:00,9:00:00,,,,,,,0,,,,,,,, +dcb9e29e-9e7a-4b65-ae2a-8c9efa816dec,0,7y7t,9:30:00,9:30:00,,,,,,,0,,,,,,,, +dcb9e29e-9e7a-4b65-ae2a-8c9efa816dec,1,zone_2,,,,2,2,,,,0,9:30:00,10:00:00,,,,,1,1 +dcb9e29e-9e7a-4b65-ae2a-8c9efa816dec,2,zone_2,,,,2,2,,,,0,9:30:00,10:00:00,,,,,1,1 +dcb9e29e-9e7a-4b65-ae2a-8c9efa816dec,3,cujv,10:00:00,10:00:00,,,,,,,0,,,,,,,, +d2a823f2-798b-476a-a222-555711ae36f9,0,7y7t,10:30:00,10:30:00,,,,,,,0,,,,,,,, +d2a823f2-798b-476a-a222-555711ae36f9,1,zone_2,,,,2,2,,,,0,10:30:00,11:00:00,,,,,1,1 +d2a823f2-798b-476a-a222-555711ae36f9,2,zone_2,,,,2,2,,,,0,10:30:00,11:00:00,,,,,1,1 +d2a823f2-798b-476a-a222-555711ae36f9,3,cujv,11:00:00,11:00:00,,,,,,,0,,,,,,,, +c4f27c33-48bb-479e-b5de-454b4eb35cdd,0,7y7t,11:30:00,11:30:00,,,,,,,0,,,,,,,, +c4f27c33-48bb-479e-b5de-454b4eb35cdd,1,zone_2,,,,2,2,,,,0,11:30:00,12:00:00,,,,,1,1 +c4f27c33-48bb-479e-b5de-454b4eb35cdd,2,zone_2,,,,2,2,,,,0,11:30:00,12:00:00,,,,,1,1 +c4f27c33-48bb-479e-b5de-454b4eb35cdd,3,cujv,12:00:00,12:00:00,,,,,,,0,,,,,,,, +ef307aa7-77da-4d0b-997f-b48493f21329,0,7y7t,14:30:00,14:30:00,,,,,,,0,,,,,,,, +ef307aa7-77da-4d0b-997f-b48493f21329,1,zone_2,,,,2,2,,,,0,14:30:00,15:00:00,,,,,1,1 +ef307aa7-77da-4d0b-997f-b48493f21329,2,zone_2,,,,2,2,,,,0,14:30:00,15:00:00,,,,,1,1 +ef307aa7-77da-4d0b-997f-b48493f21329,3,cujv,15:00:00,15:00:00,,,,,,,0,,,,,,,, +792effa3-a3a4-4cde-9246-3e70474643a1,0,7y7t,15:30:00,15:30:00,,,,,,,0,,,,,,,, +792effa3-a3a4-4cde-9246-3e70474643a1,1,zone_2,,,,2,2,,,,0,15:30:00,16:00:00,,,,,1,1 +792effa3-a3a4-4cde-9246-3e70474643a1,2,zone_2,,,,2,2,,,,0,15:30:00,16:00:00,,,,,1,1 +792effa3-a3a4-4cde-9246-3e70474643a1,3,cujv,16:00:00,16:00:00,,,,,,,0,,,,,,,, +ef5a5ad2-1db7-4005-96e6-bffbcdb50ff2,0,7y7t,12:30:00,12:30:00,,,,,,,0,,,,,,,, +ef5a5ad2-1db7-4005-96e6-bffbcdb50ff2,1,zone_2,,,,2,2,,,,0,12:30:00,13:00:00,,,,,1,1 +ef5a5ad2-1db7-4005-96e6-bffbcdb50ff2,2,zone_2,,,,2,2,,,,0,12:30:00,13:00:00,,,,,1,1 +ef5a5ad2-1db7-4005-96e6-bffbcdb50ff2,3,cujv,13:00:00,13:00:00,,,,,,,0,,,,,,,, +f2e5cf8d-290b-4da3-bc9d-b1d7ead3d6c6,0,7y7t,13:30:00,13:30:00,,,,,,,0,,,,,,,, +f2e5cf8d-290b-4da3-bc9d-b1d7ead3d6c6,1,zone_2,,,,2,2,,,,0,13:30:00,14:00:00,,,,,1,1 +f2e5cf8d-290b-4da3-bc9d-b1d7ead3d6c6,2,zone_2,,,,2,2,,,,0,13:30:00,14:00:00,,,,,1,1 +f2e5cf8d-290b-4da3-bc9d-b1d7ead3d6c6,3,cujv,14:00:00,14:00:00,,,,,,,0,,,,,,,, +c9fbc38d-4f91-46dc-bfd3-4a0460da2974,0,7y7t,16:30:00,16:30:00,,,,,,,0,,,,,,,, +c9fbc38d-4f91-46dc-bfd3-4a0460da2974,1,zone_2,,,,2,2,,,,0,16:30:00,17:00:00,,,,,1,1 +c9fbc38d-4f91-46dc-bfd3-4a0460da2974,2,zone_2,,,,2,2,,,,0,16:30:00,17:00:00,,,,,1,1 +c9fbc38d-4f91-46dc-bfd3-4a0460da2974,3,cujv,17:00:00,17:00:00,,,,,,,0,,,,,,,, +06671d42-4558-42fb-ad0f-00680b157ab7,0,7y7t,17:30:00,17:30:00,,,,,,,0,,,,,,,, +06671d42-4558-42fb-ad0f-00680b157ab7,1,zone_2,,,,2,2,,,,0,17:30:00,18:00:00,,,,,1,1 +06671d42-4558-42fb-ad0f-00680b157ab7,2,zone_2,,,,2,2,,,,0,17:30:00,18:00:00,,,,,1,1 +06671d42-4558-42fb-ad0f-00680b157ab7,3,cujv,18:00:00,18:00:00,,,,,,,0,,,,,,,, +b86afa6f-467e-4c46-8a09-5916d1cf9733,0,7y7t,18:30:00,18:30:00,,,,,,,0,,,,,,,, +b86afa6f-467e-4c46-8a09-5916d1cf9733,1,zone_2,,,,2,2,,,,0,18:30:00,19:00:00,,,,,1,1 +b86afa6f-467e-4c46-8a09-5916d1cf9733,2,zone_2,,,,2,2,,,,0,18:30:00,19:00:00,,,,,1,1 +b86afa6f-467e-4c46-8a09-5916d1cf9733,3,cujv,19:00:00,19:00:00,,,,,,,0,,,,,,,, +fe470cdb-09e4-42f9-b182-e14ddb13c15e,0,cujv,7:00:00,7:00:00,,,,,,,0,,,,,,,, +fe470cdb-09e4-42f9-b182-e14ddb13c15e,1,zone_2,,,,2,2,,,,0,7:00:00,7:30:00,,,,,1,1 +fe470cdb-09e4-42f9-b182-e14ddb13c15e,2,zone_2,,,,2,2,,,,0,7:00:00,7:30:00,,,,,1,1 +fe470cdb-09e4-42f9-b182-e14ddb13c15e,3,7y7t,7:30:00,7:30:00,,,,,,,0,,,,,,,, +d5774d48-8a06-46e0-9469-c2f881155dd6,0,cujv,8:00:00,8:00:00,,,,,,,0,,,,,,,, +d5774d48-8a06-46e0-9469-c2f881155dd6,1,zone_2,,,,2,2,,,,0,8:00:00,8:30:00,,,,,1,1 +d5774d48-8a06-46e0-9469-c2f881155dd6,2,zone_2,,,,2,2,,,,0,8:00:00,8:30:00,,,,,1,1 +d5774d48-8a06-46e0-9469-c2f881155dd6,3,7y7t,8:30:00,8:30:00,,,,,,,0,,,,,,,, +6edc3666-eee7-45fa-95d5-2d10e4923870,0,cujv,9:00:00,9:00:00,,,,,,,0,,,,,,,, +6edc3666-eee7-45fa-95d5-2d10e4923870,1,zone_2,,,,2,2,,,,0,9:00:00,9:30:00,,,,,1,1 +6edc3666-eee7-45fa-95d5-2d10e4923870,2,zone_2,,,,2,2,,,,0,9:00:00,9:30:00,,,,,1,1 +6edc3666-eee7-45fa-95d5-2d10e4923870,3,7y7t,9:30:00,9:30:00,,,,,,,0,,,,,,,, +e6a21333-9744-44d5-a926-cd92f24b1f5c,0,cujv,10:00:00,10:00:00,,,,,,,0,,,,,,,, +e6a21333-9744-44d5-a926-cd92f24b1f5c,1,zone_2,,,,2,2,,,,0,10:00:00,10:30:00,,,,,1,1 +e6a21333-9744-44d5-a926-cd92f24b1f5c,2,zone_2,,,,2,2,,,,0,10:00:00,10:30:00,,,,,1,1 +e6a21333-9744-44d5-a926-cd92f24b1f5c,3,7y7t,10:30:00,10:30:00,,,,,,,0,,,,,,,, +2e1be2a2-a953-4ae9-9d44-f1f93b0a9801,0,cujv,11:00:00,11:00:00,,,,,,,0,,,,,,,, +2e1be2a2-a953-4ae9-9d44-f1f93b0a9801,1,zone_2,,,,2,2,,,,0,11:00:00,11:30:00,,,,,1,1 +2e1be2a2-a953-4ae9-9d44-f1f93b0a9801,2,zone_2,,,,2,2,,,,0,11:00:00,11:30:00,,,,,1,1 +2e1be2a2-a953-4ae9-9d44-f1f93b0a9801,3,7y7t,11:30:00,11:30:00,,,,,,,0,,,,,,,, +e2c9bd09-af14-4e82-b6a2-ae1508e85458,0,cujv,12:00:00,12:00:00,,,,,,,0,,,,,,,, +e2c9bd09-af14-4e82-b6a2-ae1508e85458,1,zone_2,,,,2,2,,,,0,12:00:00,12:30:00,,,,,1,1 +e2c9bd09-af14-4e82-b6a2-ae1508e85458,2,zone_2,,,,2,2,,,,0,12:00:00,12:30:00,,,,,1,1 +e2c9bd09-af14-4e82-b6a2-ae1508e85458,3,7y7t,12:30:00,12:30:00,,,,,,,0,,,,,,,, +064d8fdf-7616-4ff1-b6eb-2a1f961dffd5,0,cujv,14:00:00,14:00:00,,,,,,,0,,,,,,,, +064d8fdf-7616-4ff1-b6eb-2a1f961dffd5,1,zone_2,,,,2,2,,,,0,14:00:00,14:30:00,,,,,1,1 +064d8fdf-7616-4ff1-b6eb-2a1f961dffd5,2,zone_2,,,,2,2,,,,0,14:00:00,14:30:00,,,,,1,1 +064d8fdf-7616-4ff1-b6eb-2a1f961dffd5,3,7y7t,14:30:00,14:30:00,,,,,,,0,,,,,,,, +6e9dcf78-99fe-44d5-9d1b-8f5f35bc814c,0,cujv,13:00:00,13:00:00,,,,,,,0,,,,,,,, +6e9dcf78-99fe-44d5-9d1b-8f5f35bc814c,1,zone_2,,,,2,2,,,,0,13:00:00,13:30:00,,,,,1,1 +6e9dcf78-99fe-44d5-9d1b-8f5f35bc814c,2,zone_2,,,,2,2,,,,0,13:00:00,13:30:00,,,,,1,1 +6e9dcf78-99fe-44d5-9d1b-8f5f35bc814c,3,7y7t,13:30:00,13:30:00,,,,,,,0,,,,,,,, +a77552e4-413f-4a0b-a638-0ff99b9b411d,0,cujv,15:00:00,15:00:00,,,,,,,0,,,,,,,, +a77552e4-413f-4a0b-a638-0ff99b9b411d,1,zone_2,,,,2,2,,,,0,15:00:00,15:30:00,,,,,1,1 +a77552e4-413f-4a0b-a638-0ff99b9b411d,2,zone_2,,,,2,2,,,,0,15:00:00,15:30:00,,,,,1,1 +a77552e4-413f-4a0b-a638-0ff99b9b411d,3,7y7t,15:30:00,15:30:00,,,,,,,0,,,,,,,, +21f51e8c-43f7-44ea-9f6f-c145a3c58203,0,cujv,16:00:00,16:00:00,,,,,,,0,,,,,,,, +21f51e8c-43f7-44ea-9f6f-c145a3c58203,1,zone_2,,,,2,2,,,,0,16:00:00,16:30:00,,,,,1,1 +21f51e8c-43f7-44ea-9f6f-c145a3c58203,2,zone_2,,,,2,2,,,,0,16:00:00,16:30:00,,,,,1,1 +21f51e8c-43f7-44ea-9f6f-c145a3c58203,3,7y7t,16:30:00,16:30:00,,,,,,,0,,,,,,,, +1cd920d7-e402-4e99-960c-06caaeea60b5,0,cujv,17:00:00,17:00:00,,,,,,,0,,,,,,,, +1cd920d7-e402-4e99-960c-06caaeea60b5,1,zone_2,,,,2,2,,,,0,17:00:00,17:30:00,,,,,1,1 +1cd920d7-e402-4e99-960c-06caaeea60b5,2,zone_2,,,,2,2,,,,0,17:00:00,17:30:00,,,,,1,1 +1cd920d7-e402-4e99-960c-06caaeea60b5,3,7y7t,17:30:00,17:30:00,,,,,,,0,,,,,,,, +194001c3-3e55-45b1-a8ff-3fde406bc3f1,0,cujv,18:00:00,18:00:00,,,,,,,0,,,,,,,, +194001c3-3e55-45b1-a8ff-3fde406bc3f1,1,zone_2,,,,2,2,,,,0,18:00:00,18:30:00,,,,,1,1 +194001c3-3e55-45b1-a8ff-3fde406bc3f1,2,zone_2,,,,2,2,,,,0,18:00:00,18:30:00,,,,,1,1 +194001c3-3e55-45b1-a8ff-3fde406bc3f1,3,7y7t,18:30:00,18:30:00,,,,,,,0,,,,,,,, +53f5d74e-6ee1-4cb9-a0f7-dc9ec3007ee0,0,cujv,7:00:00,7:00:00,,,,,,,0,,,,,,,, +53f5d74e-6ee1-4cb9-a0f7-dc9ec3007ee0,1,zone_3,,,,2,2,,,,0,7:00:00,7:30:00,,,,,1,1 +53f5d74e-6ee1-4cb9-a0f7-dc9ec3007ee0,2,zone_3,,,,2,2,,,,0,7:00:00,7:30:00,,,,,1,1 +53f5d74e-6ee1-4cb9-a0f7-dc9ec3007ee0,3,urnz,7:30:00,7:30:00,,,,,,,0,,,,,,,, +a326c618-d42c-4bd1-9624-c314fbf8ecd8,0,cujv,8:00:00,8:00:00,,,,,,,0,,,,,,,, +a326c618-d42c-4bd1-9624-c314fbf8ecd8,1,zone_3,,,,2,2,,,,0,8:00:00,8:30:00,,,,,1,1 +a326c618-d42c-4bd1-9624-c314fbf8ecd8,2,zone_3,,,,2,2,,,,0,8:00:00,8:30:00,,,,,1,1 +a326c618-d42c-4bd1-9624-c314fbf8ecd8,3,urnz,8:30:00,8:30:00,,,,,,,0,,,,,,,, +5e1d5f1c-6d00-49a6-bcb4-102e23473ef1,0,cujv,9:00:00,9:00:00,,,,,,,0,,,,,,,, +5e1d5f1c-6d00-49a6-bcb4-102e23473ef1,1,zone_3,,,,2,2,,,,0,9:00:00,9:30:00,,,,,1,1 +5e1d5f1c-6d00-49a6-bcb4-102e23473ef1,2,zone_3,,,,2,2,,,,0,9:00:00,9:30:00,,,,,1,1 +5e1d5f1c-6d00-49a6-bcb4-102e23473ef1,3,urnz,9:30:00,9:30:00,,,,,,,0,,,,,,,, +73c4a35b-7d18-424a-af12-9e5cb4020a82,0,cujv,10:00:00,10:00:00,,,,,,,0,,,,,,,, +73c4a35b-7d18-424a-af12-9e5cb4020a82,1,zone_3,,,,2,2,,,,0,10:00:00,10:30:00,,,,,1,1 +73c4a35b-7d18-424a-af12-9e5cb4020a82,2,zone_3,,,,2,2,,,,0,10:00:00,10:30:00,,,,,1,1 +73c4a35b-7d18-424a-af12-9e5cb4020a82,3,urnz,10:30:00,10:30:00,,,,,,,0,,,,,,,, +8327b802-1c0f-4a0f-99dd-57e2e5a5f9c5,0,cujv,11:00:00,11:00:00,,,,,,,0,,,,,,,, +8327b802-1c0f-4a0f-99dd-57e2e5a5f9c5,1,zone_3,,,,2,2,,,,0,11:00:00,11:30:00,,,,,1,1 +8327b802-1c0f-4a0f-99dd-57e2e5a5f9c5,2,zone_3,,,,2,2,,,,0,11:00:00,11:30:00,,,,,1,1 +8327b802-1c0f-4a0f-99dd-57e2e5a5f9c5,3,urnz,11:30:00,11:30:00,,,,,,,0,,,,,,,, +d8a01791-b8e2-4677-bc70-b4750a6d038a,0,cujv,12:00:00,12:00:00,,,,,,,0,,,,,,,, +d8a01791-b8e2-4677-bc70-b4750a6d038a,1,zone_3,,,,2,2,,,,0,12:00:00,12:30:00,,,,,1,1 +d8a01791-b8e2-4677-bc70-b4750a6d038a,2,zone_3,,,,2,2,,,,0,12:00:00,12:30:00,,,,,1,1 +d8a01791-b8e2-4677-bc70-b4750a6d038a,3,urnz,12:30:00,12:30:00,,,,,,,0,,,,,,,, +f53a1465-6030-4885-9f05-243867071272,0,cujv,13:00:00,13:00:00,,,,,,,0,,,,,,,, +f53a1465-6030-4885-9f05-243867071272,1,zone_3,,,,2,2,,,,0,13:00:00,13:30:00,,,,,1,1 +f53a1465-6030-4885-9f05-243867071272,2,zone_3,,,,2,2,,,,0,13:00:00,13:30:00,,,,,1,1 +f53a1465-6030-4885-9f05-243867071272,3,urnz,13:30:00,13:30:00,,,,,,,0,,,,,,,, +86e55114-94ea-4716-bbe4-7382452e83a4,0,cujv,14:00:00,14:00:00,,,,,,,0,,,,,,,, +86e55114-94ea-4716-bbe4-7382452e83a4,1,zone_3,,,,2,2,,,,0,14:00:00,14:30:00,,,,,1,1 +86e55114-94ea-4716-bbe4-7382452e83a4,2,zone_3,,,,2,2,,,,0,14:00:00,14:30:00,,,,,1,1 +86e55114-94ea-4716-bbe4-7382452e83a4,3,urnz,14:30:00,14:30:00,,,,,,,0,,,,,,,, +ef126e29-8527-407d-b3fe-b363bca9ab57,0,cujv,16:00:00,16:00:00,,,,,,,0,,,,,,,, +ef126e29-8527-407d-b3fe-b363bca9ab57,1,zone_3,,,,2,2,,,,0,16:00:00,16:30:00,,,,,1,1 +ef126e29-8527-407d-b3fe-b363bca9ab57,2,zone_3,,,,2,2,,,,0,16:00:00,16:30:00,,,,,1,1 +ef126e29-8527-407d-b3fe-b363bca9ab57,3,urnz,16:30:00,16:30:00,,,,,,,0,,,,,,,, +c11bfab9-25b8-4390-8df4-424505cbda8f,0,cujv,17:00:00,17:00:00,,,,,,,0,,,,,,,, +c11bfab9-25b8-4390-8df4-424505cbda8f,1,zone_3,,,,2,2,,,,0,17:00:00,17:30:00,,,,,1,1 +c11bfab9-25b8-4390-8df4-424505cbda8f,2,zone_3,,,,2,2,,,,0,17:00:00,17:30:00,,,,,1,1 +c11bfab9-25b8-4390-8df4-424505cbda8f,3,urnz,17:30:00,17:30:00,,,,,,,0,,,,,,,, +e5dc18ca-b8fb-49a4-8902-b13b87f738b7,0,cujv,15:00:00,15:00:00,,,,,,,0,,,,,,,, +e5dc18ca-b8fb-49a4-8902-b13b87f738b7,1,zone_3,,,,2,2,,,,0,15:00:00,15:30:00,,,,,1,1 +e5dc18ca-b8fb-49a4-8902-b13b87f738b7,2,zone_3,,,,2,2,,,,0,15:00:00,15:30:00,,,,,1,1 +e5dc18ca-b8fb-49a4-8902-b13b87f738b7,3,urnz,15:30:00,15:30:00,,,,,,,0,,,,,,,, +9fdd99ae-e7df-4439-ab9c-b91f863a6eb8,0,cujv,18:00:00,18:00:00,,,,,,,0,,,,,,,, +9fdd99ae-e7df-4439-ab9c-b91f863a6eb8,1,zone_3,,,,2,2,,,,0,18:00:00,18:30:00,,,,,1,1 +9fdd99ae-e7df-4439-ab9c-b91f863a6eb8,2,zone_3,,,,2,2,,,,0,18:00:00,18:30:00,,,,,1,1 +9fdd99ae-e7df-4439-ab9c-b91f863a6eb8,3,urnz,18:30:00,18:30:00,,,,,,,0,,,,,,,, +4c890d38-1b3a-44ca-9800-106abbdc2d7f,0,urnz,7:30:00,7:30:00,,,,,,,0,,,,,,,, +4c890d38-1b3a-44ca-9800-106abbdc2d7f,1,zone_3,,,,2,2,,,,0,7:30:00,8:00:00,,,,,1,1 +4c890d38-1b3a-44ca-9800-106abbdc2d7f,2,zone_3,,,,2,2,,,,0,7:30:00,8:00:00,,,,,1,1 +4c890d38-1b3a-44ca-9800-106abbdc2d7f,3,cujv,8:00:00,8:00:00,,,,,,,0,,,,,,,, +099936e9-ebc8-48b4-b658-a4d6ca172360,0,urnz,8:30:00,8:30:00,,,,,,,0,,,,,,,, +099936e9-ebc8-48b4-b658-a4d6ca172360,1,zone_3,,,,2,2,,,,0,8:30:00,9:00:00,,,,,1,1 +099936e9-ebc8-48b4-b658-a4d6ca172360,2,zone_3,,,,2,2,,,,0,8:30:00,9:00:00,,,,,1,1 +099936e9-ebc8-48b4-b658-a4d6ca172360,3,cujv,9:00:00,9:00:00,,,,,,,0,,,,,,,, +5f6f34cc-01c8-4f9d-a232-91072eecb085,0,urnz,11:30:00,11:30:00,,,,,,,0,,,,,,,, +5f6f34cc-01c8-4f9d-a232-91072eecb085,1,zone_3,,,,2,2,,,,0,11:30:00,12:00:00,,,,,1,1 +5f6f34cc-01c8-4f9d-a232-91072eecb085,2,zone_3,,,,2,2,,,,0,11:30:00,12:00:00,,,,,1,1 +5f6f34cc-01c8-4f9d-a232-91072eecb085,3,cujv,12:00:00,12:00:00,,,,,,,0,,,,,,,, +15122227-203e-4652-b84d-e7f6879cd93e,0,urnz,12:30:00,12:30:00,,,,,,,0,,,,,,,, +15122227-203e-4652-b84d-e7f6879cd93e,1,zone_3,,,,2,2,,,,0,12:30:00,13:00:00,,,,,1,1 +15122227-203e-4652-b84d-e7f6879cd93e,2,zone_3,,,,2,2,,,,0,12:30:00,13:00:00,,,,,1,1 +15122227-203e-4652-b84d-e7f6879cd93e,3,cujv,13:00:00,13:00:00,,,,,,,0,,,,,,,, +a562a0b1-38e5-403d-8a3c-1dab58aeac80,0,urnz,9:30:00,9:30:00,,,,,,,0,,,,,,,, +a562a0b1-38e5-403d-8a3c-1dab58aeac80,1,zone_3,,,,2,2,,,,0,9:30:00,10:00:00,,,,,1,1 +a562a0b1-38e5-403d-8a3c-1dab58aeac80,2,zone_3,,,,2,2,,,,0,9:30:00,10:00:00,,,,,1,1 +a562a0b1-38e5-403d-8a3c-1dab58aeac80,3,cujv,10:00:00,10:00:00,,,,,,,0,,,,,,,, +8823f7f0-a737-49fd-94ab-7e52cb6d1bc6,0,urnz,10:30:00,10:30:00,,,,,,,0,,,,,,,, +8823f7f0-a737-49fd-94ab-7e52cb6d1bc6,1,zone_3,,,,2,2,,,,0,10:30:00,11:00:00,,,,,1,1 +8823f7f0-a737-49fd-94ab-7e52cb6d1bc6,2,zone_3,,,,2,2,,,,0,10:30:00,11:00:00,,,,,1,1 +8823f7f0-a737-49fd-94ab-7e52cb6d1bc6,3,cujv,11:00:00,11:00:00,,,,,,,0,,,,,,,, +9657b71d-dd67-4018-adfa-50a39e6c8d96,0,urnz,13:30:00,13:30:00,,,,,,,0,,,,,,,, +9657b71d-dd67-4018-adfa-50a39e6c8d96,1,zone_3,,,,2,2,,,,0,13:30:00,14:00:00,,,,,1,1 +9657b71d-dd67-4018-adfa-50a39e6c8d96,2,zone_3,,,,2,2,,,,0,13:30:00,14:00:00,,,,,1,1 +9657b71d-dd67-4018-adfa-50a39e6c8d96,3,cujv,14:00:00,14:00:00,,,,,,,0,,,,,,,, +9b814859-a7a2-499e-9132-12439865c2e3,0,urnz,14:30:00,14:30:00,,,,,,,0,,,,,,,, +9b814859-a7a2-499e-9132-12439865c2e3,1,zone_3,,,,2,2,,,,0,14:30:00,15:00:00,,,,,1,1 +9b814859-a7a2-499e-9132-12439865c2e3,2,zone_3,,,,2,2,,,,0,14:30:00,15:00:00,,,,,1,1 +9b814859-a7a2-499e-9132-12439865c2e3,3,cujv,15:00:00,15:00:00,,,,,,,0,,,,,,,, +ae72c875-e838-4be5-a610-7fd1d204c96a,0,urnz,15:30:00,15:30:00,,,,,,,0,,,,,,,, +ae72c875-e838-4be5-a610-7fd1d204c96a,1,zone_3,,,,2,2,,,,0,15:30:00,16:00:00,,,,,1,1 +ae72c875-e838-4be5-a610-7fd1d204c96a,2,zone_3,,,,2,2,,,,0,15:30:00,16:00:00,,,,,1,1 +ae72c875-e838-4be5-a610-7fd1d204c96a,3,cujv,16:00:00,16:00:00,,,,,,,0,,,,,,,, +4fb5949c-0916-4c3d-9210-0887d632baf1,0,urnz,16:30:00,16:30:00,,,,,,,0,,,,,,,, +4fb5949c-0916-4c3d-9210-0887d632baf1,1,zone_3,,,,2,2,,,,0,16:30:00,17:00:00,,,,,1,1 +4fb5949c-0916-4c3d-9210-0887d632baf1,2,zone_3,,,,2,2,,,,0,16:30:00,17:00:00,,,,,1,1 +4fb5949c-0916-4c3d-9210-0887d632baf1,3,cujv,17:00:00,17:00:00,,,,,,,0,,,,,,,, +04c8b180-b8ec-4786-ae01-b7a15eeaeb90,0,urnz,17:30:00,17:30:00,,,,,,,0,,,,,,,, +04c8b180-b8ec-4786-ae01-b7a15eeaeb90,1,zone_3,,,,2,2,,,,0,17:30:00,18:00:00,,,,,1,1 +04c8b180-b8ec-4786-ae01-b7a15eeaeb90,2,zone_3,,,,2,2,,,,0,17:30:00,18:00:00,,,,,1,1 +04c8b180-b8ec-4786-ae01-b7a15eeaeb90,3,cujv,18:00:00,18:00:00,,,,,,,0,,,,,,,, +a92ebee3-8f29-49f0-bb57-f1c1662172f0,0,urnz,18:30:00,18:30:00,,,,,,,0,,,,,,,, +a92ebee3-8f29-49f0-bb57-f1c1662172f0,1,zone_3,,,,2,2,,,,0,18:30:00,19:00:00,,,,,1,1 +a92ebee3-8f29-49f0-bb57-f1c1662172f0,2,zone_3,,,,2,2,,,,0,18:30:00,19:00:00,,,,,1,1 +a92ebee3-8f29-49f0-bb57-f1c1662172f0,3,cujv,19:00:00,19:00:00,,,,,,,0,,,,,,,, diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stops.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stops.txt new file mode 100644 index 00000000000..0e1854c2e4c --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/stops.txt @@ -0,0 +1,5 @@ +stop_id,stop_code,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,location_type,parent_station,stop_timezone,wheelchair_boarding,platform_code +cujv,,Transfer Point for Route 30,,33.854650,-84.600390,Z4,,,,,, +yz85,,Zone 1 - PUBLIX Super Market,Zone 1 Collection Point,33.864460,-84.674200,Z1,,,,,, +7y7t,,Zone 2 - Horseshoe Bend Plaza,Zone 2 Collection Point,33.883320,-84.620270,Z2,,,,,, +urnz,,Zone 3 - Downtown Austell,Zone 3 Collection Point,33.812190,-84.634500,Z3,,,,,, diff --git a/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/trips.txt b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/trips.txt new file mode 100644 index 00000000000..8888cd8f6c6 --- /dev/null +++ b/src/ext-test/resources/flex/cobblinc-scheduled-deviated-flex.gtfs/trips.txt @@ -0,0 +1,73 @@ +trip_id,route_id,service_id,trip_headsign,trip_short_name,direction_id,block_id,shape_id,wheelchair_accessible,bikes_allowed +4d838cf4-d44d-4e08-a364-f22c34a8c89e,090z,1,,,1,,1603,, +48071338-a326-4da6-aca6-b1e0de935e5e,090z,1,,,1,,1603,, +3a4c1a1e-bbfd-46cc-8b2c-f68c7b0dca7c,090z,1,,,1,,1603,, +55db7288-4c30-47ba-b766-16a09b1d5020,090z,1,,,1,,1603,, +3570424a-a8ae-4a7c-8137-c6f6245ddfca,090z,1,,,1,,1603,, +d0cc6a8d-78c6-496a-aa3e-66c0829930f1,090z,1,,,1,,1603,, +50dfb2c0-d8ba-4dc6-a104-a3cc058feae9,090z,1,,,1,,1603,, +1d32fa36-c9db-4ca2-a26b-574935e99081,090z,1,,,1,,1603,, +273d01f4-1adb-4c9d-9fef-54c861fd15d0,090z,1,,,1,,1603,, +a642849a-c0e1-4308-b6c4-0ad12c56744c,090z,1,,,1,,1603,, +adef9bc9-98ee-4ae1-99a9-5b55bb01bf52,090z,1,,,1,,1603,, +a62fe28a-b95b-4f37-b72c-db27af73e6fe,090z,1,,,1,,1603,, +b43131c7-63c2-4127-a837-6987dcc428ae,090z,1,,,0,,cizy,, +5ad42b7b-30df-47ad-8264-b9c1119d954a,090z,1,,,0,,cizy,, +0ef63de2-f001-423e-b2c8-cb362db810dc,090z,1,,,0,,cizy,, +580c504a-d9e8-446f-8a79-efedbeda8dab,090z,1,,,0,,cizy,, +54c6c881-ec67-4a66-bd9f-3b61c83b326b,090z,1,,,0,,cizy,, +ac07359f-3afa-4de6-a076-d746cbc83ded,090z,1,,,0,,cizy,, +89367b3a-da78-4420-b497-01aa9017068d,090z,1,,,0,,cizy,, +c8bd2ce1-eff7-4504-8fd7-2416de4d9413,090z,1,,,0,,cizy,, +202bd60a-a979-4bba-86b0-d0b1e870bdfc,090z,1,,,0,,cizy,, +6cd8ea48-276d-45d7-852c-167a8f2b13fa,090z,1,,,0,,cizy,, +19290d0c-323c-499b-aa37-65cb80505d6b,090z,1,,,0,,cizy,, +f665bd4d-6f7a-4fbf-97ba-e602c17620c2,090z,1,,,0,,cizy,, +9d80fb21-203f-4e0f-b79c-5d584ebe4ffd,aamr,1,,,1,,5mw2,, +679e1454-ae4b-4c5d-a594-78c30b76843e,aamr,1,,,1,,5mw2,, +dcb9e29e-9e7a-4b65-ae2a-8c9efa816dec,aamr,1,,,1,,5mw2,, +d2a823f2-798b-476a-a222-555711ae36f9,aamr,1,,,1,,5mw2,, +c4f27c33-48bb-479e-b5de-454b4eb35cdd,aamr,1,,,1,,5mw2,, +ef307aa7-77da-4d0b-997f-b48493f21329,aamr,1,,,1,,5mw2,, +792effa3-a3a4-4cde-9246-3e70474643a1,aamr,1,,,1,,5mw2,, +ef5a5ad2-1db7-4005-96e6-bffbcdb50ff2,aamr,1,,,1,,5mw2,, +f2e5cf8d-290b-4da3-bc9d-b1d7ead3d6c6,aamr,1,,,1,,5mw2,, +c9fbc38d-4f91-46dc-bfd3-4a0460da2974,aamr,1,,,1,,5mw2,, +06671d42-4558-42fb-ad0f-00680b157ab7,aamr,1,,,1,,5mw2,, +b86afa6f-467e-4c46-8a09-5916d1cf9733,aamr,1,,,1,,5mw2,, +fe470cdb-09e4-42f9-b182-e14ddb13c15e,aamr,1,,,0,,wm2h,, +d5774d48-8a06-46e0-9469-c2f881155dd6,aamr,1,,,0,,wm2h,, +6edc3666-eee7-45fa-95d5-2d10e4923870,aamr,1,,,0,,wm2h,, +e6a21333-9744-44d5-a926-cd92f24b1f5c,aamr,1,,,0,,wm2h,, +2e1be2a2-a953-4ae9-9d44-f1f93b0a9801,aamr,1,,,0,,wm2h,, +e2c9bd09-af14-4e82-b6a2-ae1508e85458,aamr,1,,,0,,wm2h,, +064d8fdf-7616-4ff1-b6eb-2a1f961dffd5,aamr,1,,,0,,wm2h,, +6e9dcf78-99fe-44d5-9d1b-8f5f35bc814c,aamr,1,,,0,,wm2h,, +a77552e4-413f-4a0b-a638-0ff99b9b411d,aamr,1,,,0,,wm2h,, +21f51e8c-43f7-44ea-9f6f-c145a3c58203,aamr,1,,,0,,wm2h,, +1cd920d7-e402-4e99-960c-06caaeea60b5,aamr,1,,,0,,wm2h,, +194001c3-3e55-45b1-a8ff-3fde406bc3f1,aamr,1,,,0,,wm2h,, +53f5d74e-6ee1-4cb9-a0f7-dc9ec3007ee0,po0p,1,,,0,,swh2,, +a326c618-d42c-4bd1-9624-c314fbf8ecd8,po0p,1,,,0,,swh2,, +5e1d5f1c-6d00-49a6-bcb4-102e23473ef1,po0p,1,,,0,,swh2,, +73c4a35b-7d18-424a-af12-9e5cb4020a82,po0p,1,,,0,,swh2,, +8327b802-1c0f-4a0f-99dd-57e2e5a5f9c5,po0p,1,,,0,,swh2,, +d8a01791-b8e2-4677-bc70-b4750a6d038a,po0p,1,,,0,,swh2,, +f53a1465-6030-4885-9f05-243867071272,po0p,1,,,0,,swh2,, +86e55114-94ea-4716-bbe4-7382452e83a4,po0p,1,,,0,,swh2,, +ef126e29-8527-407d-b3fe-b363bca9ab57,po0p,1,,,0,,swh2,, +c11bfab9-25b8-4390-8df4-424505cbda8f,po0p,1,,,0,,swh2,, +e5dc18ca-b8fb-49a4-8902-b13b87f738b7,po0p,1,,,0,,swh2,, +9fdd99ae-e7df-4439-ab9c-b91f863a6eb8,po0p,1,,,0,,swh2,, +4c890d38-1b3a-44ca-9800-106abbdc2d7f,po0p,1,,,1,,fj8w,, +099936e9-ebc8-48b4-b658-a4d6ca172360,po0p,1,,,1,,fj8w,, +5f6f34cc-01c8-4f9d-a232-91072eecb085,po0p,1,,,1,,fj8w,, +15122227-203e-4652-b84d-e7f6879cd93e,po0p,1,,,1,,fj8w,, +a562a0b1-38e5-403d-8a3c-1dab58aeac80,po0p,1,,,1,,fj8w,, +8823f7f0-a737-49fd-94ab-7e52cb6d1bc6,po0p,1,,,1,,fj8w,, +9657b71d-dd67-4018-adfa-50a39e6c8d96,po0p,1,,,1,,fj8w,, +9b814859-a7a2-499e-9132-12439865c2e3,po0p,1,,,1,,fj8w,, +ae72c875-e838-4be5-a610-7fd1d204c96a,po0p,1,,,1,,fj8w,, +4fb5949c-0916-4c3d-9210-0887d632baf1,po0p,1,,,1,,fj8w,, +04c8b180-b8ec-4786-ae01-b7a15eeaeb90,po0p,1,,,1,,fj8w,, +a92ebee3-8f29-49f0-bb57-f1c1662172f0,po0p,1,,,1,,fj8w,, diff --git a/src/ext-test/resources/flex/lincoln-county-flex.gtfs.zip b/src/ext-test/resources/flex/lincoln-county-flex.gtfs.zip deleted file mode 100644 index f63a0bf736a0c3d74fbad6baea5e3c45bb1fa0b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 461815 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%0AdXXL)2Uv4*9CIXkQ+Q1h#g0 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 * The {@code travelDuration} is added as a criteria to the pareto comparator in addition to the - * parameters used for each stop arrivals. The {@code travelDuration} is only needed at the + * parameters used for each stop-arrival. The {@code travelDuration} is only needed at the * destination, because Range Raptor works in iterations backwards in time. */ public class PathParetoSetComparators { @@ -123,7 +122,7 @@ > ParetoComparator> comparatorTimetableAndC1() { compareIterationDepartureTime(l, r) || compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(l, r); } @@ -136,7 +135,7 @@ > ParetoComparator> comparatorTimetableAndRelaxedC1( compareIterationDepartureTime(l, r) || compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(relaxCost, l, r); } @@ -146,7 +145,7 @@ > ParetoComparator> comparatorArrivalTimeAndC1() { return (l, r) -> compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(l, r); } @@ -156,7 +155,7 @@ > ParetoComparator> comparatorDepartureTimeAndC1() { return (l, r) -> compareDepartureTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(l, r); } @@ -168,7 +167,7 @@ > ParetoComparator> comparatorArrivalTimeAndRelaxedC1( return (l, r) -> compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(relaxCost, l, r); } @@ -180,7 +179,7 @@ > ParetoComparator> comparatorDepartureTimeAndRelaxedC1( return (l, r) -> compareDepartureTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(relaxCost, l, r); } @@ -193,7 +192,7 @@ > ParetoComparator> comparatorTimetableAndC1AndC2( compareIterationDepartureTime(l, r) || compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(l, r) || c2Comp.leftDominateRight(l.c2(), r.c2()); } @@ -208,7 +207,7 @@ > ParetoComparator> comparatorTimetableAndRelaxedC1IfC2IsOptimal( compareIterationDepartureTime(l, r) || compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1RelaxedIfC2IsOptimal(l, r, relaxCost, c2Comp); } @@ -218,7 +217,7 @@ > ParetoComparator> comparatorWithC1AndC2(@Nonnull DominanceFuncti return (l, r) -> compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(l, r) || c2Comp.leftDominateRight(l.c2(), r.c2()); } @@ -231,7 +230,7 @@ > ParetoComparator> comparatorDepartureTimeAndC1AndC2( return (l, r) -> compareDepartureTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1(l, r) || c2Comp.leftDominateRight(l.c2(), r.c2()); } @@ -245,7 +244,7 @@ > ParetoComparator> comparatorArrivalTimeAndRelaxedC1IfC2IsOptimal return (l, r) -> compareArrivalTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1RelaxedIfC2IsOptimal(l, r, relaxCost, c2Comp); } @@ -258,7 +257,7 @@ > ParetoComparator> comparatorDepartureTimeAndRelaxedC1IfC2IsOptim return (l, r) -> compareDepartureTime(l, r) || compareNumberOfTransfers(l, r) || - compareDuration(l, r) || + compareDurationInclusivePenalty(l, r) || compareC1RelaxedIfC2IsOptimal(l, r, relaxCost, c2Comp); } diff --git a/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java b/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java index de6a846f480..24eae14f997 100644 --- a/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java +++ b/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java @@ -46,11 +46,21 @@ public int startTime() { return departureTime; } + @Override + public int startTimeInclusivePenalty() { + return departureTime; + } + @Override public int endTime() { return arrivalTime; } + @Override + public int endTimeInclusivePenalty() { + return arrivalTime; + } + @Override public int durationInSeconds() { return arrivalTime - departureTime; diff --git a/src/test/java/org/opentripplanner/raptor/_data/api/TestRaptorPath.java b/src/test/java/org/opentripplanner/raptor/_data/api/TestRaptorPath.java index a0ec4523726..dab47a6d18b 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/api/TestRaptorPath.java +++ b/src/test/java/org/opentripplanner/raptor/_data/api/TestRaptorPath.java @@ -3,6 +3,7 @@ import java.util.List; import java.util.stream.Stream; import javax.annotation.Nullable; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.path.AccessPathLeg; import org.opentripplanner.raptor.api.path.EgressPathLeg; @@ -18,9 +19,9 @@ */ public record TestRaptorPath( int rangeRaptorIterationDepartureTime, - int startTime, - int endTime, - int durationInSeconds, + int startTimeInclusivePenalty, + int endTimeInclusivePenalty, + int durationInclusivePenaltyInSeconds, int numberOfTransfers, int c1, int c2 @@ -29,6 +30,18 @@ public record TestRaptorPath( private static final String NOT_IMPLEMENTED_MESSAGE = "Use the real Path implementation if you need legs..."; + @Override + public int startTime() { + // This should not be used in the pareto comparison. + return RaptorConstants.TIME_NOT_SET; + } + + @Override + public int endTime() { + // This should not be used in the pareto comparison. + return RaptorConstants.TIME_NOT_SET; + } + @Override public int numberOfTransfersExAccessEgress() { throw new UnsupportedOperationException(NOT_IMPLEMENTED_MESSAGE); diff --git a/src/test/java/org/opentripplanner/raptor/api/path/RaptorPathTest.java b/src/test/java/org/opentripplanner/raptor/api/path/RaptorPathTest.java index edd45078086..5684a28c1c1 100644 --- a/src/test/java/org/opentripplanner/raptor/api/path/RaptorPathTest.java +++ b/src/test/java/org/opentripplanner/raptor/api/path/RaptorPathTest.java @@ -1,6 +1,5 @@ package org.opentripplanner.raptor.api.path; -import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -112,10 +111,10 @@ void compareArrivalTime() { @Test void compareDuration() { - assertFalse(RaptorPath.compareDuration(subject, subject)); - assertFalse(RaptorPath.compareDuration(subject, same)); - assertFalse(RaptorPath.compareDuration(subject, smallDuration)); - assertTrue(RaptorPath.compareDuration(smallDuration, subject)); + assertFalse(RaptorPath.compareDurationInclusivePenalty(subject, subject)); + assertFalse(RaptorPath.compareDurationInclusivePenalty(subject, same)); + assertFalse(RaptorPath.compareDurationInclusivePenalty(subject, smallDuration)); + assertTrue(RaptorPath.compareDurationInclusivePenalty(smallDuration, subject)); } @Test diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/support/ExpectedList.java b/src/test/java/org/opentripplanner/raptor/moduletests/support/ExpectedList.java index ce4a68b1025..bca2c31ef0e 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/support/ExpectedList.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/support/ExpectedList.java @@ -22,14 +22,6 @@ public String[] first(int n) { return range(0, n); } - public String get(int index) { - return items[index]; - } - - public String[] get(int... indexes) { - return Arrays.stream(indexes).mapToObj(i -> items[i]).toList().toArray(new String[0]); - } - public String last() { return items[items.length - 1]; } @@ -38,6 +30,14 @@ public String[] last(int n) { return range(items.length - n, items.length); } + public String get(int index) { + return items[index]; + } + + public String[] get(int... indexes) { + return Arrays.stream(indexes).mapToObj(i -> items[i]).toList().toArray(new String[0]); + } + public String[] range(int startInclusive, int endExclusive) { return Arrays.stream(items, startInclusive, endExclusive).toList().toArray(new String[0]); } From 8f363243d31a5304c998ed3d5ac4a67d1eb550a5 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 29 Feb 2024 17:45:59 +0100 Subject: [PATCH 153/183] test: Add module tests on access/egress with time-penalty --- .../L01_TimePenaltyAccessTest.java | 153 +++++++++++++++++ .../L01_TimePenaltyEgressTest.java | 158 ++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyAccessTest.java create mode 100644 src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyEgressTest.java diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyAccessTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyAccessTest.java new file mode 100644 index 00000000000..778dd36a227 --- /dev/null +++ b/src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyAccessTest.java @@ -0,0 +1,153 @@ +package org.opentripplanner.raptor.moduletests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.framework.time.TimeUtils.time; +import static org.opentripplanner.raptor._data.api.PathUtils.withoutCost; +import static org.opentripplanner.raptor._data.transit.TestAccessEgress.walk; +import static org.opentripplanner.raptor._data.transit.TestRoute.route; +import static org.opentripplanner.raptor._data.transit.TestTripSchedule.schedule; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD_ONE; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD_REV; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD_REV_ONE; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.multiCriteria; + +import java.time.Duration; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.opentripplanner.raptor.RaptorService; +import org.opentripplanner.raptor._data.RaptorTestConstants; +import org.opentripplanner.raptor._data.transit.TestTransitData; +import org.opentripplanner.raptor._data.transit.TestTripSchedule; +import org.opentripplanner.raptor.api.request.RaptorRequestBuilder; +import org.opentripplanner.raptor.configure.RaptorConfig; +import org.opentripplanner.raptor.moduletests.support.ExpectedList; +import org.opentripplanner.raptor.moduletests.support.ModuleTestDebugLogging; +import org.opentripplanner.raptor.moduletests.support.RaptorModuleTestCase; + +/* + * FEATURE UNDER TEST + * + * Raptor should take into account time-penalty for access. This test focuses on checking the + * logic for the time-penalty. The penalty should be included in the access when comparing for + * optimality, but should be excluded when checking for time constraints (arrive-by/depart-after). + * All paths in this test have the same penalty; Hence, we do not compare paths with/without a + * penalty. + */ +public class L01_TimePenaltyAccessTest implements RaptorTestConstants { + + private static final Duration D8m = Duration.ofMinutes(8); + + // There are 5 possible trips + + private final TestTransitData data = new TestTransitData(); + private final RaptorRequestBuilder requestBuilder = new RaptorRequestBuilder<>(); + private final RaptorService raptorService = new RaptorService<>( + RaptorConfig.defaultConfigForTest() + ); + + @BeforeEach + public void setup() { + data.withRoute(route("R1", STOP_A, STOP_B).withTimetable(schedule("0:10 0:40").repeat(10, 60))); + requestBuilder + .searchParams() + .addAccessPaths(walk(STOP_A, D2m).withTimePenalty(D1m)) + .addEgressPaths(walk(STOP_B, D1m)); + + requestBuilder.searchParams().timetable(true); + + ModuleTestDebugLogging.setupDebugLogging(data, requestBuilder); + } + + private static List tripsAtTheEndOfTheSearchWindowTestCase() { + int edt = time("0:01"); + int lat = time("0:42"); + + var expected = new ExpectedList( + "Walk 2m 0:08 0:10 C₁240 ~ A 0s ~ BUS R1 0:10 .. [0:08 0:41 33m Tₓ0 C₁2_760]", + "Walk 2m 0:09 0:11 C₁240 ~ A 0s ~ BUS R1 0:11 .. [0:09 0:42 33m Tₓ0 C₁2_760]" + ); + + return RaptorModuleTestCase + .of() + .withRequest(r -> + r.searchParams().earliestDepartureTime(edt).latestArrivalTime(lat).searchWindow(D8m) + ) + .addMinDuration("34m", TX_0, edt, lat) + .add(TC_STANDARD, withoutCost(expected.all())) + .add(TC_STANDARD_ONE, withoutCost(expected.first())) + .add(TC_STANDARD_REV, withoutCost(expected.all())) + .add(TC_STANDARD_REV_ONE, withoutCost(expected.last())) + .add(multiCriteria(), expected.all()) + .build(); + } + + @ParameterizedTest + @MethodSource("tripsAtTheEndOfTheSearchWindowTestCase") + void tripsAtTheEndOfTheSearchWindowTest(RaptorModuleTestCase testCase) { + assertEquals( + testCase.expected(), + focusOnAccess(testCase.runDetailedResult(raptorService, data, requestBuilder)) + ); + } + + private static List tripsAtTheBeginningOfTheSearchWindowTestCases() { + int edt = time("0:16"); + // The last path arrive at the destination at 0:50, LAT=0:55 will iterate over the last 5 + // paths. + int lat = time("0:55"); + + // The latest buss is at 0:19, so with EDT=0:16 can only reach the last two buses, + // Running this test without the time-penalty confirm this result. + var expected = new ExpectedList( + "Walk 2m 0:16 0:18 C₁240 ~ A 0s ~ BUS R1 0:18 .. [0:16 0:49 33m Tₓ0 C₁2_760]", + "Walk 2m 0:17 0:19 C₁240 ~ A 0s ~ BUS R1 0:19 .. [0:17 0:50 33m Tₓ0 C₁2_760]" + ); + + return RaptorModuleTestCase + .of() + .withRequest(r -> + r.searchParams().earliestDepartureTime(edt).latestArrivalTime(lat).searchWindow(D8m) + ) + .addMinDuration("34m", TX_0, edt, lat) + .add(TC_STANDARD, withoutCost(expected.all())) + // We do not have special support for time-penalty for single iteration Raptor, so the + // first path is missed due to the penalty. + .add(TC_STANDARD_ONE, withoutCost(expected.last())) + // Note! this test that the time-penalty is removed from the "arrive-by" limit in the + // destination + .add(TC_STANDARD_REV, withoutCost(expected.all())) + .add(TC_STANDARD_REV_ONE, withoutCost(expected.last())) + .add(multiCriteria(), expected.all()) + .build(); + } + + @ParameterizedTest + @MethodSource("tripsAtTheBeginningOfTheSearchWindowTestCases") + void tripsAtTheBeginningOfTheSearchWindowTest(RaptorModuleTestCase testCase) { + assertEquals( + testCase.expected(), + focusOnAccess(testCase.runDetailedResult(raptorService, data, requestBuilder)) + ); + } + + public static String focusOnAccess(String path) { + // We are only interested in the access and the first boarding. We include the + // pareto vector as well. + var p = Pattern.compile("(.+BUS R1 \\d+:\\d+).+(\\[.+)"); + + String[] lines = path.split("\n"); + return Stream + .of(lines) + .map(s -> { + var m = p.matcher(s); + return m.find() ? m.group(1) + " .. " + m.group(2) : s; + }) + .collect(Collectors.joining("\n")); + } +} diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyEgressTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyEgressTest.java new file mode 100644 index 00000000000..1e6897475f4 --- /dev/null +++ b/src/test/java/org/opentripplanner/raptor/moduletests/L01_TimePenaltyEgressTest.java @@ -0,0 +1,158 @@ +package org.opentripplanner.raptor.moduletests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.framework.time.TimeUtils.time; +import static org.opentripplanner.raptor._data.api.PathUtils.withoutCost; +import static org.opentripplanner.raptor._data.transit.TestAccessEgress.walk; +import static org.opentripplanner.raptor._data.transit.TestRoute.route; +import static org.opentripplanner.raptor._data.transit.TestTripSchedule.schedule; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD_ONE; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD_REV; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.TC_STANDARD_REV_ONE; +import static org.opentripplanner.raptor.moduletests.support.RaptorModuleTestConfig.multiCriteria; + +import java.time.Duration; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.opentripplanner.raptor.RaptorService; +import org.opentripplanner.raptor._data.RaptorTestConstants; +import org.opentripplanner.raptor._data.api.PathUtils; +import org.opentripplanner.raptor._data.transit.TestTransitData; +import org.opentripplanner.raptor._data.transit.TestTripSchedule; +import org.opentripplanner.raptor.api.request.RaptorRequestBuilder; +import org.opentripplanner.raptor.configure.RaptorConfig; +import org.opentripplanner.raptor.moduletests.support.ExpectedList; +import org.opentripplanner.raptor.moduletests.support.ModuleTestDebugLogging; +import org.opentripplanner.raptor.moduletests.support.RaptorModuleTestCase; + +/* + * FEATURE UNDER TEST + * + * Raptor should take into account time-penalty for egress. This test focuses on checking the + * logic for the time-penalty. The penalty should be included in the egress when comparing for + * optimality, but should be excluded when checking for time constraints (arrive-by/depart-after). + * All paths in this test have the same penalty; Hence, we do not compare paths with/without a + * penalty. + *

+ * Tip! Remove time-penalty from egress and the test should in most cases have the same result. + */ +public class L01_TimePenaltyEgressTest implements RaptorTestConstants { + + private static final Duration D8m = Duration.ofMinutes(8); + + // There are 5 possible trips + + private final TestTransitData data = new TestTransitData(); + private final RaptorRequestBuilder requestBuilder = new RaptorRequestBuilder<>(); + private final RaptorService raptorService = new RaptorService<>( + RaptorConfig.defaultConfigForTest() + ); + + @BeforeEach + public void setup() { + data.withRoute(route("R1", STOP_A, STOP_B).withTimetable(schedule("0:10 0:40").repeat(10, 60))); + requestBuilder + .searchParams() + .addAccessPaths(walk(STOP_A, D1m)) + .addEgressPaths(walk(STOP_B, D2m).withTimePenalty(D1m)); + + requestBuilder.searchParams().timetable(true); + + ModuleTestDebugLogging.setupDebugLogging(data, requestBuilder); + } + + private static List firstTwoPathsArriveBeforeLAT() { + // EDT is set to allow 5 paths - not a limiting factor. + int edt = time("0:05"); + // We limit the search to the two first paths by setting the LAT to 0:43. + int lat = time("0:43"); + + var expected = new ExpectedList( + "BUS R1 0:10 0:40 30m ~ B 0s ~ Walk 2m 0:40 0:42 [0:09 0:42 33m Tₓ0]", + "BUS R1 0:11 0:41 30m ~ B 0s ~ Walk 2m 0:41 0:43 [0:10 0:43 33m Tₓ0]" + ); + + return RaptorModuleTestCase + .of() + .withRequest(r -> + r.searchParams().earliestDepartureTime(edt).latestArrivalTime(lat).searchWindow(D8m) + ) + .addMinDuration("34m", TX_0, edt, lat) + .add(TC_STANDARD, withoutCost(expected.all())) + .add(TC_STANDARD_ONE, withoutCost(expected.first())) + .add(TC_STANDARD_REV, withoutCost(expected.all())) + // The egress time-penalty will cause the first path to be missed (singe iteration) + .add(TC_STANDARD_REV_ONE, withoutCost(expected.first())) + .add(multiCriteria(), expected.all()) + .build(); + } + + @ParameterizedTest + @MethodSource("firstTwoPathsArriveBeforeLAT") + void firstTwoPathsArriveBeforeLAT(RaptorModuleTestCase testCase) { + assertEquals( + testCase.expected(), + focusOnEgress(testCase.runDetailedResult(raptorService, data, requestBuilder)) + ); + } + + private static List lastTwoPathsDepartsAfterEDT() { + // The latest buss is at 0:19, so with EDT=0:17 can only reach the last two buses. + int edt = time("0:17"); + int lat = time("0:51"); + + var expected = new ExpectedList( + "BUS R1 0:18 0:48 30m ~ B 0s ~ Walk 2m 0:48 0:50 [0:17 0:50 33m Tₓ0]", + "BUS R1 0:19 0:49 30m ~ B 0s ~ Walk 2m 0:49 0:51 [0:18 0:51 33m Tₓ0]" + ); + + return RaptorModuleTestCase + .of() + .withRequest(r -> + r.searchParams().earliestDepartureTime(edt).latestArrivalTime(lat).searchWindow(D8m) + ) + .addMinDuration("34m", TX_0, edt, lat) + // Note! this test that the time-penalty is removed from the "arrive-by" limit in the + // destination + .add(TC_STANDARD, withoutCost(expected.all())) + .add(TC_STANDARD_ONE, withoutCost(expected.first())) + .add(TC_STANDARD_REV, withoutCost(expected.all())) + // We do not have special support for time-penalty for single iteration Raptor, so the + // "last" path is missed due to the penalty for a reverse search. + .add(TC_STANDARD_REV_ONE, withoutCost(expected.first())) + .add(multiCriteria(), expected.all()) + .build(); + } + + @ParameterizedTest + @MethodSource("lastTwoPathsDepartsAfterEDT") + void lastTwoPathsDepartsAfterEDT(RaptorModuleTestCase testCase) { + assertEquals( + testCase.expected(), + focusOnEgress(testCase.runDetailedResult(raptorService, data, requestBuilder)) + ); + } + + public static String focusOnEgress(String path) { + // We are only interested in the access and the first boarding. We include the + // pareto vector as well. + var p = Pattern.compile("(BUS R1 .+)(\\[.+)"); + + // BUS R1 0:18 0:48 30m ~ B 0s ~ Walk 1m 0:48 0:49 .. [0:16 0:49 33m Tₓ0] + String[] lines = path.split("\n"); + return Stream + .of(lines) + .map(s -> { + int pos = s.indexOf("BUS"); + return pos > 0 ? s.substring(pos) : s; + }) + .map(PathUtils::withoutCost) + .collect(Collectors.joining("\n")); + } +} From bc56933bd01208569c623281f309f85d115ba440 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:19:19 +0000 Subject: [PATCH 154/183] chore(deps): update dependency com.google.cloud.tools:jib-maven-plugin to v3.4.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 48e03115c17..d1b9c8be0ba 100644 --- a/pom.xml +++ b/pom.xml @@ -444,7 +444,7 @@ com.google.cloud.tools jib-maven-plugin - 3.4.0 + 3.4.1 org.opentripplanner.standalone.OTPMain From b833b370e477e5c2bde29911aeea05c3d0dc33c3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:19:25 +0000 Subject: [PATCH 155/183] fix(deps): update dependency ch.qos.logback:logback-classic to v1.5.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d1b9c8be0ba..9ed632e69d8 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 1.12.2 5.5.3 - 1.5.0 + 1.5.1 9.9.1 2.0.12 2.0.15 From 71415a9f2d7c2610614bf33a04fdf0d361b1065f Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 1 Mar 2024 12:16:49 +0100 Subject: [PATCH 156/183] Apply suggestions from code review Co-authored-by: Leonard Ehrenfried --- .../opentripplanner/raptor/api/model/RaptorAccessEgress.java | 2 +- .../opentripplanner/raptor/rangeraptor/transit/AccessPaths.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java b/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java index a1764d42374..aac389b7af4 100644 --- a/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java +++ b/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java @@ -55,7 +55,7 @@ public interface RaptorAccessEgress { * For example, for Park&Ride, driving all the way to the * destination is very often the best option when looking at the time criteria. When an * increasing time-penalty is applied to access/egress with driving then driving less become - * more favorable. This also improves perfomance, since we usually add a very high cost to + * more favorable. This also improves performance, since we usually add a very high cost to * driving - making all park&ride access legs optimal - forcing Raptor to compute a path for * every option. The short drives are optimal on cost, and the long are optimal on time. In the * case of park&ride the time-penalty enables Raptor to choose one of the shortest access/egress diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java index 26fb49ec88a..0e251192bc7 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java @@ -179,7 +179,7 @@ private static boolean hasTimeDependentAccess(TIntObjectMap From 2f17a31bd8125800fa2888a4089aac5a6f6a88f2 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 1 Mar 2024 12:23:41 +0100 Subject: [PATCH 157/183] doc: Add JavaDoc to the AccessPaths#iterateOverPathsWithPenalty method --- .../raptor/rangeraptor/transit/AccessPaths.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java index 0e251192bc7..d070a804f9c 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java @@ -110,6 +110,11 @@ public int calculateMaxNumberOfRides() { ); } + /** + * This is used in the main "minutes" iteration to iterate over the extra minutes needed to + * include access with time-penalty. This method returns an iterator for the minutes in front of + * the normal search window starting at the given {@code earliestDepartureTime}. + */ public IntIterator iterateOverPathsWithPenalty(final int earliestDepartureTime) { if (!hasTimePenalty()) { return IntIterators.empty(); From 4758a77a6b38750bb8fb036b79672561680ff372 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 1 Mar 2024 12:40:40 +0100 Subject: [PATCH 158/183] refactor: Use a constant fixed implementation for IntIterator#empty() --- .../opentripplanner/raptor/util/IntIterators.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/raptor/util/IntIterators.java b/src/main/java/org/opentripplanner/raptor/util/IntIterators.java index cb8c6c38787..b0df1e56155 100644 --- a/src/main/java/org/opentripplanner/raptor/util/IntIterators.java +++ b/src/main/java/org/opentripplanner/raptor/util/IntIterators.java @@ -1,9 +1,22 @@ package org.opentripplanner.raptor.util; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.spi.IntIterator; public class IntIterators { + private static final IntIterator EMPTY = new IntIterator() { + @Override + public int next() { + return RaptorConstants.NOT_FOUND; + } + + @Override + public boolean hasNext() { + return false; + } + }; + /** This is private to forbid construction. */ private IntIterators() { /* NOOP*/ @@ -122,6 +135,6 @@ public static IntIterator singleValueIterator(final int value) { * Return an empty iterator. All calls to {@link IntIterator#hasNext()} will return {@code false}. */ public static IntIterator empty() { - return intIncIterator(0, 0); + return EMPTY; } } From 5bd379973e30d31d43aaba66661f07be4afd9e0c Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 1 Mar 2024 12:51:36 +0100 Subject: [PATCH 159/183] refactor: Cleanup RaptorTestConstants --- .../opentripplanner/raptor/_data/RaptorTestConstants.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/opentripplanner/raptor/_data/RaptorTestConstants.java b/src/test/java/org/opentripplanner/raptor/_data/RaptorTestConstants.java index d1398ea05cd..0bca83be8bf 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/RaptorTestConstants.java +++ b/src/test/java/org/opentripplanner/raptor/_data/RaptorTestConstants.java @@ -28,18 +28,14 @@ public interface RaptorTestConstants { int D24h = durationInSeconds("24h"); /** - * There are 86400 seconds in a "normal" day(24 * 60 * 60). This is used for testing, logging - * and debugging, but does not base any important logic on this. A day with changes in - * daylight-saving-time does not have this number of seconds. + * There are 86400 seconds in a "normal" day(24 * 60 * 60). */ int SECONDS_IN_A_DAY = (int) D24h; // Time constants, all values are in seconds int T00_00 = hm2time(0, 0); - int T00_01 = hm2time(0, 1); int T00_02 = hm2time(0, 2); int T00_10 = hm2time(0, 10); - int T00_12 = hm2time(0, 12); int T00_30 = hm2time(0, 30); int T00_40 = hm2time(0, 40); int T01_00 = hm2time(1, 0); @@ -49,7 +45,7 @@ public interface RaptorTestConstants { int TX_2 = 2; // Stop indexes - Note! There is no stop defined for index 0(zero)! You must - // account for that in the test if you uses a stop index. + // account for that in the test if you use the stop index. int STOP_A = 1; int STOP_B = 2; int STOP_C = 3; From ed3d05aad648726ce5d3768ddba0167140335e24 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 1 Mar 2024 13:04:01 +0100 Subject: [PATCH 160/183] Apply suggestions from code review Co-authored-by: Johan Torin --- .../framework/lang/MemEfficientArrayBuilder.java | 6 +++--- .../opentripplanner/transit/model/network/TripPattern.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/lang/MemEfficientArrayBuilder.java b/src/main/java/org/opentripplanner/framework/lang/MemEfficientArrayBuilder.java index 161ac5c5cf5..8b3a6ba6cd0 100644 --- a/src/main/java/org/opentripplanner/framework/lang/MemEfficientArrayBuilder.java +++ b/src/main/java/org/opentripplanner/framework/lang/MemEfficientArrayBuilder.java @@ -5,13 +5,13 @@ import javax.annotation.Nonnull; /** - * This array builder is used to minimize creating new objects(arrays). It takes an array as base, + * This array builder is used to minimize the creation of new objects (arrays). It takes an array as base, * the original array. A new array is created only if there are differences. *

* A common case is that one original is updated several times. In this case, you can use the - * {@link #build(Object[])}, too also make sure the existing update is reused (deduplicated). + * {@link #build(Object[])} method to also make sure that the existing update is reused (deduplicated). *

- * Arrays are mutable, so be careful this class helps you reuse the original if it has the same + * Arrays are mutable, so be careful as this class helps you reuse the original if it has the same * values. It protects the original while in scope, but you should only use it if you do not * modify the original or the result on the outside. This builder does not help protect the arrays. */ diff --git a/src/main/java/org/opentripplanner/transit/model/network/TripPattern.java b/src/main/java/org/opentripplanner/transit/model/network/TripPattern.java index a439c9fd4fe..7e40aa2d13b 100644 --- a/src/main/java/org/opentripplanner/transit/model/network/TripPattern.java +++ b/src/main/java/org/opentripplanner/transit/model/network/TripPattern.java @@ -161,7 +161,7 @@ public StopPattern getStopPattern() { /** * Return the "original"/planned stop pattern as a builder. This is used when a realtime-update - * contains a full set of stops/pickup/droppoff for a pattern. This will wipe out any changes + * contains a full set of stops/pickup/dropoff for a pattern. This will wipe out any changes * to the stop-pattern from previous updates. *

* Be aware, if the same update is applied twice, then the first instance will be reused to avoid From 7fd489235ca656dff6e5e011221068bb526656bd Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 1 Mar 2024 14:27:31 +0100 Subject: [PATCH 161/183] Run apt-get update before install [ci skip] --- .github/workflows/post-merge.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index a2f29f0d1b0..86f3741aada 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -54,6 +54,7 @@ jobs: - name: Install xmllint run: | + sudo apt-get update sudo apt-get install -y libxml2-utils - name: Configure git user From 2b07ff88f13e6d82db97981fed17492ae35cade0 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 1 Mar 2024 15:56:31 +0200 Subject: [PATCH 162/183] Bump serialization version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9ed632e69d8..d746c259a25 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ - 146 + 147 30.2 2.51 From 0136bbd59b3f5fd24cfaea9c90d448de6b4c8b12 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 1 Mar 2024 16:03:42 +0100 Subject: [PATCH 163/183] Apply review feedback --- .../areastops/AreaStopsLayerBuilderTest.java | 47 ++++++++++--------- .../areastops/AreaStopPropertyMapper.java | 2 +- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopsLayerBuilderTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopsLayerBuilderTest.java index befaa6b886d..2e6c4e16c40 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopsLayerBuilderTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopsLayerBuilderTest.java @@ -1,6 +1,7 @@ package org.opentripplanner.ext.vectortiles.layers.areastops; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.standalone.config.framework.json.JsonSupport.newNodeAdapterForTest; import java.util.List; import java.util.Locale; @@ -9,6 +10,7 @@ import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.inspector.vector.LayerParameters; +import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.site.AreaStop; @@ -21,6 +23,28 @@ class AreaStopsLayerBuilderTest { private static final FeedScopedId ID = new FeedScopedId("FEED", "ID"); private static final I18NString NAME = I18NString.of("Test stop"); + private static final String CONFIG = + """ + { + "vectorTiles": { + "layers" : [ + { + "name": "areaStops", + "type": "AreaStop", + "mapper": "OTPRR", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0 + } + ] + } + } + """; + private static final LayerParameters LAYER_CONFIG = VectorTileConfig + .mapVectorTilesParameters(newNodeAdapterForTest(CONFIG), "vectorTiles") + .layers() + .getFirst(); private final StopModelBuilder stopModelBuilder = StopModel.of(); @@ -35,34 +59,13 @@ class AreaStopsLayerBuilderTest { new Deduplicator() ); - record Layer( - String name, - VectorTilesResource.LayerType type, - String mapper, - int maxZoom, - int minZoom, - int cacheMaxSeconds, - double expansionFactor - ) - implements LayerParameters {} - @Test void getAreaStops() { transitModel.index(); - var layer = new Layer( - "areaStops", - VectorTilesResource.LayerType.AreaStop, - "OTPRR", - 20, - 1, - 10, - .25 - ); - var subject = new AreaStopsLayerBuilder( new DefaultTransitService(transitModel), - layer, + LAYER_CONFIG, Locale.ENGLISH ); var geometries = subject.getGeometries(AREA_STOP.getGeometry().getEnvelopeInternal()); diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopPropertyMapper.java index c91ea2cb6b6..ea6f9225e11 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopPropertyMapper.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/areastops/AreaStopPropertyMapper.java @@ -40,7 +40,7 @@ protected Collection map(AreaStop stop) { .filter(Objects::nonNull) .distinct() // the MVT spec explicitly doesn't cover how to encode arrays - // https://docs.mapbox.com/data/tilesets/guides/vector-tiles-standards/ + // https://docs.mapbox.com/data/tilesets/guides/vector-tiles-standards/#what-the-spec-doesnt-cover .collect(Collectors.joining(",")); return List.of( new KeyValue("gtfsId", stop.getId().toString()), From 8ea6935f94957402bf3c8164bcc7ff94fff01211 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 01:06:48 +0000 Subject: [PATCH 164/183] fix(deps): update dependency ch.qos.logback:logback-classic to v1.5.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d746c259a25..7075f575344 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 1.12.2 5.5.3 - 1.5.1 + 1.5.2 9.9.1 2.0.12 2.0.15 From 28865d50f9ea4a14af08f9ff936c585313f41923 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 01:06:54 +0000 Subject: [PATCH 165/183] chore(deps): update dependency org.mockito:mockito-core to v5.11.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7075f575344..8764dc0578a 100644 --- a/pom.xml +++ b/pom.xml @@ -713,7 +713,7 @@ org.mockito mockito-core - 5.10.0 + 5.11.0 test From 5bf60ef3b90547a4016ab84c7800c4d23a205fc7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 1 Mar 2024 23:00:51 +0100 Subject: [PATCH 166/183] Migrate from VariableSource to MethodSource --- ...CombinedInterlinedLegsFareServiceTest.java | 18 +- .../ext/fares/model/FareProductTest.java | 42 +-- .../RideHailingAccessShifterTest.java | 44 +-- .../gtfs/mapping/RouteRequestMapperTest.java | 81 ++--- .../mapping/TripRequestMapperTest.java | 11 +- .../scalars/DateTimeScalarFactoryTest.java | 22 +- .../framework/lang/StringUtilsTest.java | 20 +- .../graph_builder/module/GtfsFeedIdTest.java | 8 +- .../OsmBoardingLocationsModuleTest.java | 26 +- .../interlining/InterlineProcessorTest.java | 110 +++---- .../gtfs/mapping/LocationMapperTest.java | 11 +- .../gtfs/mapping/TransitModeMapperTest.java | 24 +- .../opentripplanner/model/plan/PlaceTest.java | 22 +- .../model/plan/RelativeDirectionTest.java | 52 ++-- .../OSMOpeningHoursParserTest.java | 286 +++++++++--------- .../tagmapping/PortlandMapperTest.java | 37 +-- .../specifier/BestMatchSpecifierTest.java | 18 +- .../wayproperty/specifier/ConditionTest.java | 70 +++-- .../transit/TripPatternForDateTest.java | 12 +- .../cost/WheelchairCostCalculatorTest.java | 16 +- ...eRequestTransitDataProviderFilterTest.java | 22 +- .../services/TransferGeneratorTest.java | 32 +- .../request/WheelchairPreferencesTest.java | 82 ++--- .../LinearFunctionSerializationTest.java | 38 +-- .../TimeSlopeSafetyTriangleTest.java | 26 +- .../routing/core/MoneyTest.java | 48 +-- .../routerequest/WheelchairConfigTest.java | 96 +++--- .../server/EtagRequestFilterTest.java | 34 ++- .../server/RequestTraceFilterTest.java | 32 +- .../model/edge/ElevatorHopEdgeTest.java | 30 +- .../street/model/edge/EscalatorEdgeTest.java | 8 +- .../street/model/edge/PathwayEdgeTest.java | 34 ++- .../street/model/edge/StreetEdgeCostTest.java | 80 ++--- .../edge/StreetEdgeRentalTraversalTest.java | 30 +- .../edge/StreetEdgeWheelchairCostTest.java | 82 ++--- .../edge/StreetVehicleParkingLinkTest.java | 24 +- .../street/search/state/StateDataTest.java | 12 +- .../street/search/state/StateTest.java | 44 +-- .../support/VariableArgumentsProvider.java | 55 ---- .../test/support/VariableSource.java | 19 -- .../trip/TimetableSnapshotSourceTest.java | 20 +- .../RealtimeVehicleMatcherTest.java | 16 +- 42 files changed, 905 insertions(+), 889 deletions(-) delete mode 100644 src/test/java/org/opentripplanner/test/support/VariableArgumentsProvider.java delete mode 100644 src/test/java/org/opentripplanner/test/support/VariableSource.java diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java index 3f237cf509f..407cd0f11e9 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java @@ -16,12 +16,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.ext.fares.impl.CombinedInterlinedLegsFareService.CombinationMode; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.PlanTestConstants; import org.opentripplanner.routing.core.FareType; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.network.Route; @@ -44,17 +44,19 @@ class CombinedInterlinedLegsFareServiceTest implements PlanTestConstants { static Money tenDollars = Money.usDollars(10); static Money twentyDollars = Money.usDollars(20); - static Stream testCases = Stream.of( - Arguments.of(ALWAYS, interlinedWithSameRoute, tenDollars, "same routes"), - Arguments.of(ALWAYS, interlinedWithDifferentRoute, tenDollars, "different routes"), - Arguments.of(SAME_ROUTE, interlinedWithSameRoute, tenDollars, "same routes"), - Arguments.of(SAME_ROUTE, interlinedWithDifferentRoute, twentyDollars, "different routes") - ); + static Stream testCases() { + return Stream.of( + Arguments.of(ALWAYS, interlinedWithSameRoute, tenDollars, "same routes"), + Arguments.of(ALWAYS, interlinedWithDifferentRoute, tenDollars, "different routes"), + Arguments.of(SAME_ROUTE, interlinedWithSameRoute, tenDollars, "same routes"), + Arguments.of(SAME_ROUTE, interlinedWithDifferentRoute, twentyDollars, "different routes") + ); + } @ParameterizedTest( name = "Itinerary with {3} and combination mode {0} should lead to a fare of {2}" ) - @VariableSource("testCases") + @MethodSource("testCases") void modes(CombinationMode mode, Itinerary itinerary, Money totalPrice, String hint) { var service = new CombinedInterlinedLegsFareService(mode); service.addFareRules( diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/model/FareProductTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/model/FareProductTest.java index 9edcecb7567..089bac64c11 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/model/FareProductTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/model/FareProductTest.java @@ -9,10 +9,10 @@ import javax.annotation.Nonnull; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.model.fare.FareMedium; import org.opentripplanner.model.fare.FareProduct; import org.opentripplanner.model.fare.RiderCategory; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.framework.FeedScopedId; @@ -28,27 +28,29 @@ class FareProductTest { static FareMedium MEDIUM = new FareMedium(new FeedScopedId("1", "app"), "App"); - static Stream testCases = Stream.of( - Arguments.of(fareProduct(null, null, null), ZDT, "b18a083d-ee82-3c83-af07-2b8bb11bff9e"), - Arguments.of( - fareProduct(null, null, null), - ZDT.plusHours(1), - "2a60adcf-3e56-338a-ab7d-8407a3bc529b" - ), - Arguments.of( - fareProduct(Duration.ofHours(2), CATEGORY, null), - ZDT, - "ca4a45b5-b837-34d8-b987-4e06fa5a3317" - ), - Arguments.of( - fareProduct(Duration.ofHours(2), CATEGORY, MEDIUM), - ZDT, - "b59e7eef-c118-37b1-8f53-bf2a97c5dae9" - ) - ); + static Stream testCases() { + return Stream.of( + Arguments.of(fareProduct(null, null, null), ZDT, "b18a083d-ee82-3c83-af07-2b8bb11bff9e"), + Arguments.of( + fareProduct(null, null, null), + ZDT.plusHours(1), + "2a60adcf-3e56-338a-ab7d-8407a3bc529b" + ), + Arguments.of( + fareProduct(Duration.ofHours(2), CATEGORY, null), + ZDT, + "ca4a45b5-b837-34d8-b987-4e06fa5a3317" + ), + Arguments.of( + fareProduct(Duration.ofHours(2), CATEGORY, MEDIUM), + ZDT, + "b59e7eef-c118-37b1-8f53-bf2a97c5dae9" + ) + ); + } @ParameterizedTest - @VariableSource("testCases") + @MethodSource("testCases") void instanceId(FareProduct fareProduct, ZonedDateTime startTime, String expectedInstanceId) { var instanceId = fareProduct.uniqueInstanceId(startTime); diff --git a/src/ext-test/java/org/opentripplanner/ext/ridehailing/RideHailingAccessShifterTest.java b/src/ext-test/java/org/opentripplanner/ext/ridehailing/RideHailingAccessShifterTest.java index 465697bf197..3e6df7135e5 100644 --- a/src/ext-test/java/org/opentripplanner/ext/ridehailing/RideHailingAccessShifterTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/ridehailing/RideHailingAccessShifterTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.model.GenericLocation; import org.opentripplanner.routing.algorithm.raptoradapter.transit.DefaultAccessEgress; @@ -24,7 +25,6 @@ import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.search.state.State; import org.opentripplanner.street.search.state.TestStateBuilder; -import org.opentripplanner.test.support.VariableSource; class RideHailingAccessShifterTest { @@ -42,21 +42,23 @@ class RideHailingAccessShifterTest { List.of() ); - static Stream testCases = Stream.of( - // leave now, so shift by 10 minutes - Arguments.of(TIME, DEFAULT_ARRIVAL_DURATION), - // only shift by 9 minutes because we are wanting to leave in 1 minute - Arguments.of(TIME.plus(ofMinutes(1)), ofMinutes(9)), - // only shift by 7 minutes because we are wanting to leave in 3 minutes - Arguments.of(TIME.plus(ofMinutes(3)), ofMinutes(7)), - // no shifting because it's far in the future - Arguments.of(TIME.plus(ofMinutes(15)), ZERO), - Arguments.of(TIME.plus(ofMinutes(30)), ZERO), - Arguments.of(TIME.plus(ofMinutes(40)), ZERO) - ); + static Stream testCases() { + return Stream.of( + // leave now, so shift by 10 minutes + Arguments.of(TIME, DEFAULT_ARRIVAL_DURATION), + // only shift by 9 minutes because we are wanting to leave in 1 minute + Arguments.of(TIME.plus(ofMinutes(1)), ofMinutes(9)), + // only shift by 7 minutes because we are wanting to leave in 3 minutes + Arguments.of(TIME.plus(ofMinutes(3)), ofMinutes(7)), + // no shifting because it's far in the future + Arguments.of(TIME.plus(ofMinutes(15)), ZERO), + Arguments.of(TIME.plus(ofMinutes(30)), ZERO), + Arguments.of(TIME.plus(ofMinutes(40)), ZERO) + ); + } @ParameterizedTest - @VariableSource("testCases") + @MethodSource("testCases") void testArrivalDelay(Instant searchTime, Duration expectedArrival) { var req = new RouteRequest(); req.setTo(FROM); @@ -73,14 +75,16 @@ void testArrivalDelay(Instant searchTime, Duration expectedArrival) { assertEquals(expectedArrival, actualArrival); } - static Stream accessShiftCases = Stream.of( - // leave now, so shift by 10 minutes - Arguments.of(TIME, TIME.plus(DEFAULT_ARRIVAL_DURATION)), - Arguments.of(TIME.plus(Duration.ofHours(4)), TIME) - ); + static Stream accessShiftCases() { + return Stream.of( + // leave now, so shift by 10 minutes + Arguments.of(TIME, TIME.plus(DEFAULT_ARRIVAL_DURATION)), + Arguments.of(TIME.plus(Duration.ofHours(4)), TIME) + ); + } @ParameterizedTest - @VariableSource("accessShiftCases") + @MethodSource("accessShiftCases") void shiftAccesses(Instant startTime, Instant expectedStartTime) { var drivingState = TestStateBuilder.ofDriving().streetEdge().streetEdge().build(); var access = new DefaultAccessEgress(0, drivingState); diff --git a/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java b/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java index ecba3320838..22a8583d705 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.TestRoutingService; @@ -34,7 +35,6 @@ import org.opentripplanner.service.realtimevehicles.internal.DefaultRealtimeVehicleService; import org.opentripplanner.service.vehiclerental.internal.DefaultVehicleRentalService; import org.opentripplanner.street.search.TraverseMode; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.TransitModel; @@ -91,25 +91,30 @@ void parkingFilters() { testParkingFilters(routeRequest.preferences().parking(TraverseMode.BICYCLE)); } - static Stream banningCases = Stream.of( - of(Map.of(), "[TransitFilterRequest{}]"), - of( - Map.of("routes", "trimet:555"), - "[TransitFilterRequest{not: [SelectRequest{transportModes: [], routes: [trimet:555]}]}]" - ), - of(Map.of("agencies", ""), "[TransitFilterRequest{not: [SelectRequest{transportModes: []}]}]"), - of( - Map.of("agencies", "trimet:666"), - "[TransitFilterRequest{not: [SelectRequest{transportModes: [], agencies: [trimet:666]}]}]" - ), - of( - Map.of("agencies", "trimet:666", "routes", "trimet:444"), - "[TransitFilterRequest{not: [SelectRequest{transportModes: [], routes: [trimet:444]}, SelectRequest{transportModes: [], agencies: [trimet:666]}]}]" - ) - ); + static Stream banningCases() { + return Stream.of( + of(Map.of(), "[TransitFilterRequest{}]"), + of( + Map.of("routes", "trimet:555"), + "[TransitFilterRequest{not: [SelectRequest{transportModes: [], routes: [trimet:555]}]}]" + ), + of( + Map.of("agencies", ""), + "[TransitFilterRequest{not: [SelectRequest{transportModes: []}]}]" + ), + of( + Map.of("agencies", "trimet:666"), + "[TransitFilterRequest{not: [SelectRequest{transportModes: [], agencies: [trimet:666]}]}]" + ), + of( + Map.of("agencies", "trimet:666", "routes", "trimet:444"), + "[TransitFilterRequest{not: [SelectRequest{transportModes: [], routes: [trimet:444]}, SelectRequest{transportModes: [], agencies: [trimet:666]}]}]" + ) + ); + } @ParameterizedTest - @VariableSource("banningCases") + @MethodSource("banningCases") void banning(Map banned, String expectedFilters) { Map arguments = Map.of("banned", banned); @@ -119,21 +124,23 @@ void banning(Map banned, String expectedFilters) { assertEquals(expectedFilters, routeRequest.journey().transit().filters().toString()); } - static Stream transportModesCases = Stream.of( - of(List.of(), "[ExcludeAllTransitFilter{}]"), - of(List.of(mode("BICYCLE")), "[ExcludeAllTransitFilter{}]"), - of( - List.of(mode("BUS")), - "[TransitFilterRequest{select: [SelectRequest{transportModes: [BUS, COACH]}]}]" - ), - of( - List.of(mode("BUS"), mode("MONORAIL")), - "[TransitFilterRequest{select: [SelectRequest{transportModes: [BUS, COACH, MONORAIL]}]}]" - ) - ); + static Stream transportModesCases() { + return Stream.of( + of(List.of(), "[ExcludeAllTransitFilter{}]"), + of(List.of(mode("BICYCLE")), "[ExcludeAllTransitFilter{}]"), + of( + List.of(mode("BUS")), + "[TransitFilterRequest{select: [SelectRequest{transportModes: [BUS, COACH]}]}]" + ), + of( + List.of(mode("BUS"), mode("MONORAIL")), + "[TransitFilterRequest{select: [SelectRequest{transportModes: [BUS, COACH, MONORAIL]}]}]" + ) + ); + } @ParameterizedTest - @VariableSource("transportModesCases") + @MethodSource("transportModesCases") void modes(List> modes, String expectedFilters) { Map arguments = Map.of("transportModes", modes); @@ -172,13 +179,15 @@ void bikeTriangle() { ); } - static Stream noTriangleCases = Arrays - .stream(GraphQLTypes.GraphQLOptimizeType.values()) - .filter(value -> value != GraphQLTypes.GraphQLOptimizeType.TRIANGLE) - .map(Arguments::of); + static Stream noTriangleCases() { + return Arrays + .stream(GraphQLTypes.GraphQLOptimizeType.values()) + .filter(value -> value != GraphQLTypes.GraphQLOptimizeType.TRIANGLE) + .map(Arguments::of); + } @ParameterizedTest - @VariableSource("noTriangleCases") + @MethodSource("noTriangleCases") void noTriangle(GraphQLTypes.GraphQLOptimizeType bot) { Map arguments = Map.of( "optimize", diff --git a/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java index c0bd96b6310..e35f198d16e 100644 --- a/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.apis.transmodel.TransmodelRequestContext; import org.opentripplanner.ext.emissions.DefaultEmissionsService; @@ -50,7 +51,6 @@ import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.street.model.StreetLimitationParameters; import org.opentripplanner.street.service.DefaultStreetLimitationParametersService; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.network.Route; @@ -279,13 +279,12 @@ void testDefaultTriangleFactors() { assertEquals(TimeSlopeSafetyTriangle.DEFAULT, req2.preferences().bike().optimizeTriangle()); } - static Stream noTriangleCases = VehicleRoutingOptimizeType - .nonTriangleValues() - .stream() - .map(Arguments::of); + static Stream noTriangleCases() { + return VehicleRoutingOptimizeType.nonTriangleValues().stream().map(Arguments::of); + } @ParameterizedTest - @VariableSource("noTriangleCases") + @MethodSource("noTriangleCases") public void testBikeTriangleFactorsHasNoEffect(VehicleRoutingOptimizeType bot) { Map arguments = Map.of( "bicycleOptimisationMethod", diff --git a/src/test/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactoryTest.java b/src/test/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactoryTest.java index 43b44cbd5a6..c46c232751f 100644 --- a/src/test/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactoryTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactoryTest.java @@ -13,7 +13,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; class DateTimeScalarFactoryTest { @@ -32,17 +32,19 @@ void serialize() { assertEquals(DATE_TIME, result); } - static Stream testCases = Stream.of( - Arguments.of(DATE_TIME), - Arguments.of("2023-01-27T12:59:00.000+01:00"), - Arguments.of("2023-01-27T12:59:00+0100"), - Arguments.of("2023-01-27T12:59:00+01"), - Arguments.of("2023-01-27T12:59:00"), - Arguments.of("2023-01-27T11:59:00Z") - ); + static Stream testCases() { + return Stream.of( + Arguments.of(DATE_TIME), + Arguments.of("2023-01-27T12:59:00.000+01:00"), + Arguments.of("2023-01-27T12:59:00+0100"), + Arguments.of("2023-01-27T12:59:00+01"), + Arguments.of("2023-01-27T12:59:00"), + Arguments.of("2023-01-27T11:59:00Z") + ); + } @ParameterizedTest - @VariableSource("testCases") + @MethodSource("testCases") void parse(String input) { var result = subject.getCoercing().parseValue(input); assertEquals(EPOCH_MILLIS, result); diff --git a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java index 8998d82a5f2..9a4c30e1329 100644 --- a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java @@ -10,20 +10,22 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; class StringUtilsTest { - static final Stream hasValueTestCases = Stream.of( - Arguments.of("Text", TRUE), - Arguments.of("T", TRUE), - Arguments.of(null, FALSE), - Arguments.of("", FALSE), - Arguments.of("\t\n", FALSE) - ); + static Stream hasValueTestCases() { + return Stream.of( + Arguments.of("Text", TRUE), + Arguments.of("T", TRUE), + Arguments.of(null, FALSE), + Arguments.of("", FALSE), + Arguments.of("\t\n", FALSE) + ); + } @ParameterizedTest - @VariableSource("hasValueTestCases") + @MethodSource("hasValueTestCases") void hasValue(String input, Boolean hasValue) { assertEquals(hasValue, StringUtils.hasValue(input)); assertEquals(!hasValue, StringUtils.hasNoValue(input)); diff --git a/src/test/java/org/opentripplanner/graph_builder/module/GtfsFeedIdTest.java b/src/test/java/org/opentripplanner/graph_builder/module/GtfsFeedIdTest.java index 71a1d382983..133ec71070a 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/GtfsFeedIdTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/GtfsFeedIdTest.java @@ -9,16 +9,18 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; class GtfsFeedIdTest { private static final String NUMBERS_ONLY_REGEX = "^\\d+$"; - static Stream emptyCases = Stream.of(null, "", " ", "\n", " ").map(Arguments::of); + static Stream emptyCases() { + return Stream.of(null, "", " ", "\n", " ").map(Arguments::of); + } @ParameterizedTest - @VariableSource("emptyCases") + @MethodSource("emptyCases") void autogenerateNumber(String id) { String feedId = feedId(id); assertTrue(feedId.matches(NUMBERS_ONLY_REGEX), "'%s' is not an integer.".formatted(feedId)); diff --git a/src/test/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModuleTest.java b/src/test/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModuleTest.java index 41c77f5df6e..1d8d819b5cb 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModuleTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModuleTest.java @@ -9,6 +9,7 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.graph_builder.module.osm.OsmModule; import org.opentripplanner.openstreetmap.OsmProvider; @@ -23,7 +24,6 @@ import org.opentripplanner.street.model.vertex.VertexFactory; import org.opentripplanner.street.model.vertex.VertexLabel; import org.opentripplanner.test.support.ResourceLoader; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.model.framework.Deduplicator; @@ -49,21 +49,23 @@ class OsmBoardingLocationsModuleTest { RegularStop busStop = testModel.stop("de:08115:4512:5:C", 48.59434, 8.86452).build(); RegularStop floatingBusStop = testModel.stop("floating-bus-stop", 48.59417, 8.86464).build(); - static Stream testCases = Stream.of( - Arguments.of( - false, - Stream - .of(302563833L, 3223067049L, 302563836L, 3223067680L, 302563834L, 768590748L, 302563839L) - .map(VertexLabel::osm) - .collect(Collectors.toSet()) - ), - Arguments.of(true, Set.of(VertexLabel.osm(3223067049L), VertexLabel.osm(768590748))) - ); + static Stream testCases() { + return Stream.of( + Arguments.of( + false, + Stream + .of(302563833L, 3223067049L, 302563836L, 3223067680L, 302563834L, 768590748L, 302563839L) + .map(VertexLabel::osm) + .collect(Collectors.toSet()) + ), + Arguments.of(true, Set.of(VertexLabel.osm(3223067049L), VertexLabel.osm(768590748))) + ); + } @ParameterizedTest( name = "add boarding locations and link them to platform edges when skipVisibility={0}" ) - @VariableSource("testCases") + @MethodSource("testCases") void addAndLinkBoardingLocations(boolean areaVisibility, Set linkedVertices) { var deduplicator = new Deduplicator(); var graph = new Graph(deduplicator); diff --git a/src/test/java/org/opentripplanner/gtfs/interlining/InterlineProcessorTest.java b/src/test/java/org/opentripplanner/gtfs/interlining/InterlineProcessorTest.java index 1e931589204..67ca61f0403 100644 --- a/src/test/java/org/opentripplanner/gtfs/interlining/InterlineProcessorTest.java +++ b/src/test/java/org/opentripplanner/gtfs/interlining/InterlineProcessorTest.java @@ -10,12 +10,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.mapping.StaySeatedNotAllowed; import org.opentripplanner.model.calendar.CalendarServiceData; import org.opentripplanner.model.plan.PlanTestConstants; import org.opentripplanner.model.transfer.DefaultTransferService; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.framework.FeedScopedId; @@ -35,63 +35,65 @@ class InterlineProcessorTest implements PlanTestConstants { tripPattern("trip-5", "block-2", "service-4") ); - static Stream interlineTestCases = Stream.of( - Arguments.of( - List.of( - new FeedScopedId("1", "service-1"), - new FeedScopedId("1", "service-2"), - new FeedScopedId("1", "service-3"), - new FeedScopedId("1", "service-4") + static Stream interlineTestCases() { + return Stream.of( + Arguments.of( + List.of( + new FeedScopedId("1", "service-1"), + new FeedScopedId("1", "service-2"), + new FeedScopedId("1", "service-3"), + new FeedScopedId("1", "service-4") + ), + List.of( + List.of(LocalDate.of(2023, Month.JANUARY, 1), LocalDate.of(2023, Month.JANUARY, 5)), + List.of(LocalDate.of(2023, Month.JANUARY, 1)), + List.of(LocalDate.of(2023, Month.JANUARY, 1)), + List.of(LocalDate.of(2023, Month.JANUARY, 1)) + ), + "[ConstrainedTransfer{from: TripTP{F:trip-2, stopPos 2}, to: TripTP{F:trip-3, stopPos 0}, " + + "constraint: {staySeated}}, ConstrainedTransfer{from: TripTP{F:trip-1, stopPos 2}, " + + "to: TripTP{F:trip-2, stopPos 0}, constraint: {staySeated}}, " + + "ConstrainedTransfer{from: TripTP{F:trip-3, stopPos 2}, to: TripTP{F:trip-4, stopPos 0}, constraint: {staySeated}}]" ), - List.of( - List.of(LocalDate.of(2023, Month.JANUARY, 1), LocalDate.of(2023, Month.JANUARY, 5)), - List.of(LocalDate.of(2023, Month.JANUARY, 1)), - List.of(LocalDate.of(2023, Month.JANUARY, 1)), - List.of(LocalDate.of(2023, Month.JANUARY, 1)) + Arguments.of( + List.of( + new FeedScopedId("1", "service-1"), + new FeedScopedId("1", "service-2"), + new FeedScopedId("1", "service-3"), + new FeedScopedId("1", "service-4") + ), + List.of( + List.of(LocalDate.of(2023, Month.JANUARY, 1), LocalDate.of(2023, Month.JANUARY, 5)), + List.of(LocalDate.of(2023, Month.JANUARY, 1)), + List.of(LocalDate.of(2023, Month.JANUARY, 5)), + List.of(LocalDate.of(2023, Month.JANUARY, 1)) + ), + "[ConstrainedTransfer{from: TripTP{F:trip-2, stopPos 2}, to: TripTP{F:trip-3, stopPos 0}, " + + "constraint: {staySeated}}, ConstrainedTransfer{from: TripTP{F:trip-1, stopPos 2}, " + + "to: TripTP{F:trip-2, stopPos 0}, constraint: {staySeated}}, " + + "ConstrainedTransfer{from: TripTP{F:trip-2, stopPos 2}, to: TripTP{F:trip-4, stopPos 0}, constraint: {staySeated}}]" ), - "[ConstrainedTransfer{from: TripTP{F:trip-2, stopPos 2}, to: TripTP{F:trip-3, stopPos 0}, " + - "constraint: {staySeated}}, ConstrainedTransfer{from: TripTP{F:trip-1, stopPos 2}, " + - "to: TripTP{F:trip-2, stopPos 0}, constraint: {staySeated}}, " + - "ConstrainedTransfer{from: TripTP{F:trip-3, stopPos 2}, to: TripTP{F:trip-4, stopPos 0}, constraint: {staySeated}}]" - ), - Arguments.of( - List.of( - new FeedScopedId("1", "service-1"), - new FeedScopedId("1", "service-2"), - new FeedScopedId("1", "service-3"), - new FeedScopedId("1", "service-4") - ), - List.of( - List.of(LocalDate.of(2023, Month.JANUARY, 1), LocalDate.of(2023, Month.JANUARY, 5)), - List.of(LocalDate.of(2023, Month.JANUARY, 1)), - List.of(LocalDate.of(2023, Month.JANUARY, 5)), - List.of(LocalDate.of(2023, Month.JANUARY, 1)) - ), - "[ConstrainedTransfer{from: TripTP{F:trip-2, stopPos 2}, to: TripTP{F:trip-3, stopPos 0}, " + - "constraint: {staySeated}}, ConstrainedTransfer{from: TripTP{F:trip-1, stopPos 2}, " + - "to: TripTP{F:trip-2, stopPos 0}, constraint: {staySeated}}, " + - "ConstrainedTransfer{from: TripTP{F:trip-2, stopPos 2}, to: TripTP{F:trip-4, stopPos 0}, constraint: {staySeated}}]" - ), - // No common days between services - Arguments.of( - List.of( - new FeedScopedId("1", "service-1"), - new FeedScopedId("1", "service-2"), - new FeedScopedId("1", "service-3"), - new FeedScopedId("1", "service-4") - ), - List.of( - List.of(LocalDate.of(2023, Month.JANUARY, 1), LocalDate.of(2023, Month.JANUARY, 5)), - List.of(LocalDate.of(2023, Month.JANUARY, 2)), - List.of(LocalDate.of(2023, Month.JANUARY, 3)), - List.of(LocalDate.of(2023, Month.JANUARY, 1)) - ), - "[ConstrainedTransfer{from: TripTP{F:trip-1, stopPos 2}, to: TripTP{F:trip-2, stopPos 0}, constraint: {staySeated}}]" - ) - ); + // No common days between services + Arguments.of( + List.of( + new FeedScopedId("1", "service-1"), + new FeedScopedId("1", "service-2"), + new FeedScopedId("1", "service-3"), + new FeedScopedId("1", "service-4") + ), + List.of( + List.of(LocalDate.of(2023, Month.JANUARY, 1), LocalDate.of(2023, Month.JANUARY, 5)), + List.of(LocalDate.of(2023, Month.JANUARY, 2)), + List.of(LocalDate.of(2023, Month.JANUARY, 3)), + List.of(LocalDate.of(2023, Month.JANUARY, 1)) + ), + "[ConstrainedTransfer{from: TripTP{F:trip-1, stopPos 2}, to: TripTP{F:trip-2, stopPos 0}, constraint: {staySeated}}]" + ) + ); + } @ParameterizedTest(name = "{0} services with {1} dates should generate transfers: {2}") - @VariableSource("interlineTestCases") + @MethodSource("interlineTestCases") void testInterline( List serviceIds, List> serviceDates, diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/LocationMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/LocationMapperTest.java index e7a291fa976..4461c5a31f1 100644 --- a/src/test/java/org/opentripplanner/gtfs/mapping/LocationMapperTest.java +++ b/src/test/java/org/opentripplanner/gtfs/mapping/LocationMapperTest.java @@ -8,20 +8,19 @@ import org.geojson.Polygon; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.onebusaway.gtfs.model.AgencyAndId; import org.onebusaway.gtfs.model.Location; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.service.StopModel; class LocationMapperTest { - static Stream testCases = Stream.of( - Arguments.of(null, true), - Arguments.of("a name", false) - ); + static Stream testCases() { + return Stream.of(Arguments.of(null, true), Arguments.of("a name", false)); + } @ParameterizedTest(name = "a name of <{0}> should set bogusName={1}") - @VariableSource("testCases") + @MethodSource("testCases") void testMapping(String name, boolean isBogusName) { var gtfsLocation = new Location(); gtfsLocation.setId(new AgencyAndId("1", "zone-3")); diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/TransitModeMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/TransitModeMapperTest.java index 39973a769c0..b2e5b1a8a4d 100644 --- a/src/test/java/org/opentripplanner/gtfs/mapping/TransitModeMapperTest.java +++ b/src/test/java/org/opentripplanner/gtfs/mapping/TransitModeMapperTest.java @@ -7,23 +7,25 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.transit.model.basic.TransitMode; class TransitModeMapperTest { - static Stream testCases = Stream.of( - Arguments.of(1500, TAXI), - Arguments.of(1510, TAXI), - Arguments.of(1551, CARPOOL), - Arguments.of(1555, CARPOOL), - Arguments.of(1560, CARPOOL), - Arguments.of(1561, TAXI), - Arguments.of(1580, TAXI) - ); + static Stream testCases() { + return Stream.of( + Arguments.of(1500, TAXI), + Arguments.of(1510, TAXI), + Arguments.of(1551, CARPOOL), + Arguments.of(1555, CARPOOL), + Arguments.of(1560, CARPOOL), + Arguments.of(1561, TAXI), + Arguments.of(1580, TAXI) + ); + } @ParameterizedTest(name = "{0} should map to {1}") - @VariableSource("testCases") + @MethodSource("testCases") void map(int mode, TransitMode expectedMode) { assertEquals(expectedMode, TransitModeMapper.mapMode(mode)); } diff --git a/src/test/java/org/opentripplanner/model/plan/PlaceTest.java b/src/test/java/org/opentripplanner/model/plan/PlaceTest.java index 573e4597e39..95d7cf629a2 100644 --- a/src/test/java/org/opentripplanner/model/plan/PlaceTest.java +++ b/src/test/java/org/opentripplanner/model/plan/PlaceTest.java @@ -9,13 +9,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.street.model.vertex.SimpleVertex; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.site.RegularStop; @@ -65,17 +65,19 @@ public void sameLocationBasedOnStopId() { assertFalse(otherPlace.sameLocation(aPlace), "other place(symmetric)"); } - static Stream flexStopCases = Stream.of( - Arguments.of(null, "an intersection name"), - Arguments.of(new NonLocalizedString("1:stop_id"), "an intersection name (part of 1:stop_id)"), - Arguments.of( - new NonLocalizedString("Flex Zone 123"), - "an intersection name (part of Flex Zone 123)" - ) - ); + static Stream flexStopCases() { + return Stream.of( + Arguments.of(null, "an intersection name"), + Arguments.of(new NonLocalizedString("1:stop_id"), "an intersection name (part of 1:stop_id)"), + Arguments.of( + new NonLocalizedString("Flex Zone 123"), + "an intersection name (part of Flex Zone 123)" + ) + ); + } @ParameterizedTest(name = "Flex stop name of {0} should lead to a place name of {1}") - @VariableSource("flexStopCases") + @MethodSource("flexStopCases") public void flexStop(I18NString stopName, String expectedPlaceName) { var stop = StopModel .of() diff --git a/src/test/java/org/opentripplanner/model/plan/RelativeDirectionTest.java b/src/test/java/org/opentripplanner/model/plan/RelativeDirectionTest.java index c60861d28f8..c3cb4e0a78c 100644 --- a/src/test/java/org/opentripplanner/model/plan/RelativeDirectionTest.java +++ b/src/test/java/org/opentripplanner/model/plan/RelativeDirectionTest.java @@ -15,37 +15,39 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; class RelativeDirectionTest { @SuppressWarnings("unused") - static Stream testCasesNormal = Stream.of( - // Turn Right - tc(0, CONTINUE), - tc(17, CONTINUE), - tc(18, SLIGHTLY_RIGHT), - tc(40, SLIGHTLY_RIGHT), - tc(41, RIGHT), - tc(114, RIGHT), - tc(115, HARD_RIGHT), - tc(179, HARD_RIGHT), - tc(180, HARD_LEFT), - // Turn Left - tc(0, CONTINUE), - tc(-17, CONTINUE), - tc(-18, SLIGHTLY_LEFT), - tc(-40, SLIGHTLY_LEFT), - tc(-41, LEFT), - tc(-114, LEFT), - tc(-115, HARD_LEFT), - tc(-179, HARD_LEFT), - tc(-180, HARD_LEFT), - tc(-181, HARD_RIGHT) - ); + static Stream testCasesNormal() { + return Stream.of( + // Turn Right + tc(0, CONTINUE), + tc(17, CONTINUE), + tc(18, SLIGHTLY_RIGHT), + tc(40, SLIGHTLY_RIGHT), + tc(41, RIGHT), + tc(114, RIGHT), + tc(115, HARD_RIGHT), + tc(179, HARD_RIGHT), + tc(180, HARD_LEFT), + // Turn Left + tc(0, CONTINUE), + tc(-17, CONTINUE), + tc(-18, SLIGHTLY_LEFT), + tc(-40, SLIGHTLY_LEFT), + tc(-41, LEFT), + tc(-114, LEFT), + tc(-115, HARD_LEFT), + tc(-179, HARD_LEFT), + tc(-180, HARD_LEFT), + tc(-181, HARD_RIGHT) + ); + } @ParameterizedTest(name = "Turning {0} degrees should give a relative direction of {1}") - @VariableSource("testCasesNormal") + @MethodSource("testCasesNormal") void testCalculateForNormalIntersections(int thisAngleDegrees, RelativeDirection expected) { assertEquals(expected, RelativeDirection.calculate(angle(thisAngleDegrees), false)); } diff --git a/src/test/java/org/opentripplanner/openstreetmap/OSMOpeningHoursParserTest.java b/src/test/java/org/opentripplanner/openstreetmap/OSMOpeningHoursParserTest.java index f1068bb8220..34f141e8504 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/OSMOpeningHoursParserTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/OSMOpeningHoursParserTest.java @@ -12,9 +12,9 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.model.calendar.openinghours.OpeningHoursCalendarService; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model.framework.Deduplicator; public class OSMOpeningHoursParserTest { @@ -30,150 +30,152 @@ public class OSMOpeningHoursParserTest { ZoneIds.PARIS ); - static Stream osmOpeningHoursTestCases = Stream.of( - Arguments.of( - "Mo-Fr 14:00-19:00", - List.of("2022-10-25T14:30:00Z"), - List.of("2022-10-25T08:30:00Z", "2022-10-29T14:30:00Z") - ), - Arguments.of( - "Tu 10:00-15:00", - List.of("2022-10-25T10:30:00Z"), - List.of("2022-10-26T00:30:00Z", "2022-10-27T10:30:00Z") - ), - Arguments.of( - "Mo-Fr 08:00-17:00;Sa-Su 10:00-13:00", - List.of("2022-10-25T07:30:00Z", "2022-10-29T10:30:00Z"), - List.of("2022-10-25T03:30:00Z", "2022-10-29T15:30:00Z") - ), - // TODO implement support for public holidays, currently only the first two rules are handled - Arguments.of( - "Mo-Fr 08:00-17:00;Sa-Su 10:00-13:00; PH off", - List.of("2022-10-25T07:30:00Z", "2022-10-29T10:30:00Z"), - List.of("2022-10-25T03:30:00Z", "2022-10-29T15:30:00Z") - ), - // TODO implement support for public holidays, currently only the first two rules are handled - Arguments.of( - "Mo,We,Th,Fr,Su 00:00-24:00; Tu,Sa 00:00-02:00, 14:30-24:00; PH 00:00-24:00", - List.of("2022-10-24T15:30:00Z", "2022-10-24T23:30:00Z", "2022-10-25T15:30:00Z"), - List.of("2022-10-25T05:30:00Z") - ), - // The second rule overrides the first rule for Wednesdays, i.e. on Wednesdays it should only be - // open from 10:00 to 13:00 - Arguments.of( - "Mo-Fr 16:00-02:00; We 10:00-13:00", - List.of("2022-10-25T23:30:00Z", "2022-10-26T10:30:00Z", "2022-10-27T23:30:00Z"), - List.of("2022-10-25T10:30:00Z", "2022-10-26T23:30:00Z") - ), - // The second rule overrides the first rule for Tuesdays, i.e. it should be closed on Tuesdays - Arguments.of( - "Mo - Sa 10:00-18:00; Tu off", - List.of("2022-10-24T15:30:00Z"), - List.of("2022-10-24T05:30:00Z", "2022-10-25T10:30:00Z") - ), - // Even though the following rules are not additive, they should be handled as such because they - // have the off modifier (https://github.com/opening-hours/opening_hours.js/issues/53). - // Therefore, it should be open according to the first rule outside of the defined off periods, - // so for example, on Tuesdays it should be open from 07:30 to 12:00 and from 16:00 to 22:00. - // These different off cases are needed because they overlap slightly differently with the first - // rule and have slightly different handling in code. - Arguments.of( - "Mo-Sa 07:30-22:00; Mo 05:00-23:00 off; Tu 12:00-16:00 off; We 06:00-16:00 off; Th 07:30-16:00 off, Fr 16:00-22:00 off, Sa 16:00-23:00 off", - List.of( - "2022-10-25T07:30:00Z", - "2022-10-25T17:30:00Z", - "2022-10-26T17:30:00Z", - "2022-10-27T17:30:00Z", - "2022-10-28T07:30:00Z", - "2022-10-29T07:30:00Z" - ), - List.of( - "2022-10-24T07:30:00Z", - "2022-10-25T12:30:00Z", - "2022-10-26T07:30:00Z", - "2022-10-27T07:30:00Z", - "2022-10-28T16:30:00Z", - "2022-10-29T16:30:00Z", - "2022-10-30T07:30:00Z" + static Stream osmOpeningHoursTestCases() { + return Stream.of( + Arguments.of( + "Mo-Fr 14:00-19:00", + List.of("2022-10-25T14:30:00Z"), + List.of("2022-10-25T08:30:00Z", "2022-10-29T14:30:00Z") + ), + Arguments.of( + "Tu 10:00-15:00", + List.of("2022-10-25T10:30:00Z"), + List.of("2022-10-26T00:30:00Z", "2022-10-27T10:30:00Z") + ), + Arguments.of( + "Mo-Fr 08:00-17:00;Sa-Su 10:00-13:00", + List.of("2022-10-25T07:30:00Z", "2022-10-29T10:30:00Z"), + List.of("2022-10-25T03:30:00Z", "2022-10-29T15:30:00Z") + ), + // TODO implement support for public holidays, currently only the first two rules are handled + Arguments.of( + "Mo-Fr 08:00-17:00;Sa-Su 10:00-13:00; PH off", + List.of("2022-10-25T07:30:00Z", "2022-10-29T10:30:00Z"), + List.of("2022-10-25T03:30:00Z", "2022-10-29T15:30:00Z") + ), + // TODO implement support for public holidays, currently only the first two rules are handled + Arguments.of( + "Mo,We,Th,Fr,Su 00:00-24:00; Tu,Sa 00:00-02:00, 14:30-24:00; PH 00:00-24:00", + List.of("2022-10-24T15:30:00Z", "2022-10-24T23:30:00Z", "2022-10-25T15:30:00Z"), + List.of("2022-10-25T05:30:00Z") + ), + // The second rule overrides the first rule for Wednesdays, i.e. on Wednesdays it should only be + // open from 10:00 to 13:00 + Arguments.of( + "Mo-Fr 16:00-02:00; We 10:00-13:00", + List.of("2022-10-25T23:30:00Z", "2022-10-26T10:30:00Z", "2022-10-27T23:30:00Z"), + List.of("2022-10-25T10:30:00Z", "2022-10-26T23:30:00Z") + ), + // The second rule overrides the first rule for Tuesdays, i.e. it should be closed on Tuesdays + Arguments.of( + "Mo - Sa 10:00-18:00; Tu off", + List.of("2022-10-24T15:30:00Z"), + List.of("2022-10-24T05:30:00Z", "2022-10-25T10:30:00Z") + ), + // Even though the following rules are not additive, they should be handled as such because they + // have the off modifier (https://github.com/opening-hours/opening_hours.js/issues/53). + // Therefore, it should be open according to the first rule outside of the defined off periods, + // so for example, on Tuesdays it should be open from 07:30 to 12:00 and from 16:00 to 22:00. + // These different off cases are needed because they overlap slightly differently with the first + // rule and have slightly different handling in code. + Arguments.of( + "Mo-Sa 07:30-22:00; Mo 05:00-23:00 off; Tu 12:00-16:00 off; We 06:00-16:00 off; Th 07:30-16:00 off, Fr 16:00-22:00 off, Sa 16:00-23:00 off", + List.of( + "2022-10-25T07:30:00Z", + "2022-10-25T17:30:00Z", + "2022-10-26T17:30:00Z", + "2022-10-27T17:30:00Z", + "2022-10-28T07:30:00Z", + "2022-10-29T07:30:00Z" + ), + List.of( + "2022-10-24T07:30:00Z", + "2022-10-25T12:30:00Z", + "2022-10-26T07:30:00Z", + "2022-10-27T07:30:00Z", + "2022-10-28T16:30:00Z", + "2022-10-29T16:30:00Z", + "2022-10-30T07:30:00Z" + ) + ), + // This tests that it's correctly closed outside with an off rule that extends over midnight + Arguments.of( + "Mo-Fr 12:30-04:00; We 18:00-02:00 off", + List.of( + "2022-10-25T19:30:00Z", + "2022-10-25T23:30:00Z", + "2022-10-26T13:30:00Z", + "2022-10-27T01:30:00Z", + "2022-10-27T23:30:00Z" + ), + List.of("2022-10-26T19:30:00Z", "2022-10-26T23:30:00Z", "2022-10-27T05:30:00Z") + ), + Arguments.of( + "open; Tu 13:00-16:00 off", + List.of("2022-10-24T12:30:00Z", "2022-10-25T07:30:00Z", "2022-10-24T18:30:00Z"), + List.of("2022-10-25T13:30:00Z") + ), + Arguments.of( + "Su-Tu 11:00-02:00, We-Th 11:00-03:00, Fr 11:00-06:00, Sa 11:00-07:00", + List.of("2022-10-25T14:30:00Z", "2022-10-25T23:30:00Z", "2022-10-29T03:30:00Z"), + List.of("2022-10-25T02:30:00Z", "2022-10-27T03:30:00Z") + ), + Arguments.of( + "Sep-Oct: Mo-Sa 10:00-02:00", + List.of("2022-09-30T23:30:00Z", "2022-10-29T10:30:00Z", "2022-10-31T23:30:00Z"), + List.of("2022-10-30T10:30:00Z", "2022-11-26T10:30:00Z") + ), + Arguments.of( + "Oct: Mo 10:00-02:00", + List.of("2022-10-24T10:30:00Z", "2022-10-31T23:30:00Z"), + List.of("2022-09-30T23:30:00Z", "2022-10-30T10:30:00Z", "2022-11-07T10:30:00Z") + ), + // TODO implement support for dates with and without year, this is now completely unparsed + // which means that it's never open + Arguments.of("Oct 23-Jan 3: 10:00-23:00", List.of(), List.of("2022-10-20T12:30:00Z")), + // TODO implement support for nth weekday in a month and offsets + Arguments.of( + "Mar Su[-1]-Oct Su[1] -2 days: 22:00-23:00", + List.of(), + List.of("2022-11-20T12:30:00Z") + ), + Arguments.of("24/7", List.of("2022-10-25T07:30:00Z"), List.of()), + Arguments.of("24/7 closed", List.of(), List.of("2022-10-25T07:30:00Z")), + // TODO implement support for school holidays and special dates, only the first rule is now + // handled + Arguments.of( + "Mo-Su,SH 15:00-03:00; easter -2 days off", + List.of("2022-10-25T15:30:00Z"), + List.of("2022-10-25T05:30:00Z") + ), + // TODO implement support for comment modifiers, this is now interpreted to be always closed + Arguments.of("\"by appointment\"", List.of(), List.of("2022-10-25T07:30:00Z")), + // TODO implement support for fallbacks if feasible, now the last rule is ignored and the first + // rule is respected + Arguments.of( + "Mo-Sa 08:00-13:00,16:00-18:00 || \"by appointment\"", + List.of("2022-10-25T07:30:00Z", "2022-10-25T15:30:00Z"), + List.of("2022-10-25T13:30:00Z", "2022-10-30T07:30:00Z") + ), + // TODO implement support for weeks, these rules are now ignored and it's always closed + Arguments.of( + "week 1-53/2 Fr 09:00-12:00; week 2-52/2 We 09:00-12:00", + List.of(), + List.of("2022-10-28T07:30:00Z") + ), + // TODO implement support for events, this is now interpreted to be always closed + Arguments.of("sunrise-sunset", List.of(), List.of("2022-10-25T07:30:00Z")), + // This is interpreted to be open on sundays from 10:00 until 23:59 + Arguments.of( + "Su 10:00+", + List.of("2022-10-30T10:30:00Z"), + List.of("2022-10-25T10:30:00Z", "2022-10-30T06:30:00Z") ) - ), - // This tests that it's correctly closed outside with an off rule that extends over midnight - Arguments.of( - "Mo-Fr 12:30-04:00; We 18:00-02:00 off", - List.of( - "2022-10-25T19:30:00Z", - "2022-10-25T23:30:00Z", - "2022-10-26T13:30:00Z", - "2022-10-27T01:30:00Z", - "2022-10-27T23:30:00Z" - ), - List.of("2022-10-26T19:30:00Z", "2022-10-26T23:30:00Z", "2022-10-27T05:30:00Z") - ), - Arguments.of( - "open; Tu 13:00-16:00 off", - List.of("2022-10-24T12:30:00Z", "2022-10-25T07:30:00Z", "2022-10-24T18:30:00Z"), - List.of("2022-10-25T13:30:00Z") - ), - Arguments.of( - "Su-Tu 11:00-02:00, We-Th 11:00-03:00, Fr 11:00-06:00, Sa 11:00-07:00", - List.of("2022-10-25T14:30:00Z", "2022-10-25T23:30:00Z", "2022-10-29T03:30:00Z"), - List.of("2022-10-25T02:30:00Z", "2022-10-27T03:30:00Z") - ), - Arguments.of( - "Sep-Oct: Mo-Sa 10:00-02:00", - List.of("2022-09-30T23:30:00Z", "2022-10-29T10:30:00Z", "2022-10-31T23:30:00Z"), - List.of("2022-10-30T10:30:00Z", "2022-11-26T10:30:00Z") - ), - Arguments.of( - "Oct: Mo 10:00-02:00", - List.of("2022-10-24T10:30:00Z", "2022-10-31T23:30:00Z"), - List.of("2022-09-30T23:30:00Z", "2022-10-30T10:30:00Z", "2022-11-07T10:30:00Z") - ), - // TODO implement support for dates with and without year, this is now completely unparsed - // which means that it's never open - Arguments.of("Oct 23-Jan 3: 10:00-23:00", List.of(), List.of("2022-10-20T12:30:00Z")), - // TODO implement support for nth weekday in a month and offsets - Arguments.of( - "Mar Su[-1]-Oct Su[1] -2 days: 22:00-23:00", - List.of(), - List.of("2022-11-20T12:30:00Z") - ), - Arguments.of("24/7", List.of("2022-10-25T07:30:00Z"), List.of()), - Arguments.of("24/7 closed", List.of(), List.of("2022-10-25T07:30:00Z")), - // TODO implement support for school holidays and special dates, only the first rule is now - // handled - Arguments.of( - "Mo-Su,SH 15:00-03:00; easter -2 days off", - List.of("2022-10-25T15:30:00Z"), - List.of("2022-10-25T05:30:00Z") - ), - // TODO implement support for comment modifiers, this is now interpreted to be always closed - Arguments.of("\"by appointment\"", List.of(), List.of("2022-10-25T07:30:00Z")), - // TODO implement support for fallbacks if feasible, now the last rule is ignored and the first - // rule is respected - Arguments.of( - "Mo-Sa 08:00-13:00,16:00-18:00 || \"by appointment\"", - List.of("2022-10-25T07:30:00Z", "2022-10-25T15:30:00Z"), - List.of("2022-10-25T13:30:00Z", "2022-10-30T07:30:00Z") - ), - // TODO implement support for weeks, these rules are now ignored and it's always closed - Arguments.of( - "week 1-53/2 Fr 09:00-12:00; week 2-52/2 We 09:00-12:00", - List.of(), - List.of("2022-10-28T07:30:00Z") - ), - // TODO implement support for events, this is now interpreted to be always closed - Arguments.of("sunrise-sunset", List.of(), List.of("2022-10-25T07:30:00Z")), - // This is interpreted to be open on sundays from 10:00 until 23:59 - Arguments.of( - "Su 10:00+", - List.of("2022-10-30T10:30:00Z"), - List.of("2022-10-25T10:30:00Z", "2022-10-30T06:30:00Z") - ) - ); + ); + } @ParameterizedTest(name = "{0} should be open on {1} but not on {2}") - @VariableSource("osmOpeningHoursTestCases") + @MethodSource("osmOpeningHoursTestCases") void testOSMOpeningHoursParsing( String openingHours, List openTimes, diff --git a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/PortlandMapperTest.java b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/PortlandMapperTest.java index 06369baddc8..26f45fd8c32 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/PortlandMapperTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/PortlandMapperTest.java @@ -18,30 +18,33 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.openstreetmap.model.OSMWithTags; import org.opentripplanner.openstreetmap.wayproperty.WayPropertySet; -import org.opentripplanner.test.support.VariableSource; public class PortlandMapperTest { static double delta = 0.1; static WayPropertySet wps = new WayPropertySet(); - static Stream cases = Stream.of( - Arguments.of(southeastLaBonitaWay(), 0.8), - Arguments.of(southwestMayoStreet(), 0.9), - Arguments.of(sidewalkBoth(), 0.96), - Arguments.of(pedestrianTunnel(), 1.0), - Arguments.of(highwayTertiaryWithSidewalk(), 1.056), - Arguments.of(cobblestones(), 1.2), - Arguments.of(noSidewalk(), 1.2), - Arguments.of(carTunnel(), 1.2), - Arguments.of(footwaySidewalk(), 1.32), - Arguments.of(highwayTertiary(), 1.32), - Arguments.of(highwayTrunk(), 1.44), - Arguments.of(fiveLanes(), 1.584), - Arguments.of(noSidewalkHighSpeed(), 7.19) - ); + + static Stream cases() { + return Stream.of( + Arguments.of(southeastLaBonitaWay(), 0.8), + Arguments.of(southwestMayoStreet(), 0.9), + Arguments.of(sidewalkBoth(), 0.96), + Arguments.of(pedestrianTunnel(), 1.0), + Arguments.of(highwayTertiaryWithSidewalk(), 1.056), + Arguments.of(cobblestones(), 1.2), + Arguments.of(noSidewalk(), 1.2), + Arguments.of(carTunnel(), 1.2), + Arguments.of(footwaySidewalk(), 1.32), + Arguments.of(highwayTertiary(), 1.32), + Arguments.of(highwayTrunk(), 1.44), + Arguments.of(fiveLanes(), 1.584), + Arguments.of(noSidewalkHighSpeed(), 7.19) + ); + } static { var source = new PortlandMapper(); @@ -49,7 +52,7 @@ public class PortlandMapperTest { } @ParameterizedTest(name = "way {0} should have walk safety factor {1}") - @VariableSource("cases") + @MethodSource("cases") void walkSafety(OSMWithTags way, double expected) { var score = wps.getDataForWay(way); diff --git a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/BestMatchSpecifierTest.java b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/BestMatchSpecifierTest.java index 19575c9312f..517e4b57bfd 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/BestMatchSpecifierTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/BestMatchSpecifierTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.openstreetmap.model.OSMWithTags; -import org.opentripplanner.test.support.VariableSource; class BestMatchSpecifierTest extends SpecifierTest { @@ -48,17 +48,19 @@ void leftRightMatch() { assertEquals(100, result.forward()); } - static Stream leftRightTestCases = Stream.of( - Arguments.of(cyclewayLeft(), bikeLane, 210, 100), - Arguments.of(cyclewayLaneTrack(), cyclewayTrack, 100, 210), - Arguments.of(cyclewayLaneTrack(), highwayFootwayCyclewayLane, 210, 100), - Arguments.of(cyclewayLaneTrack(), cyclewayLane, 110, 0) - ); + static Stream leftRightTestCases() { + return Stream.of( + Arguments.of(cyclewayLeft(), bikeLane, 210, 100), + Arguments.of(cyclewayLaneTrack(), cyclewayTrack, 100, 210), + Arguments.of(cyclewayLaneTrack(), highwayFootwayCyclewayLane, 210, 100), + Arguments.of(cyclewayLaneTrack(), cyclewayLane, 110, 0) + ); + } @ParameterizedTest( name = "way {0} with specifier {1} should have a backward score {2} and forward score {3}" ) - @VariableSource("leftRightTestCases") + @MethodSource("leftRightTestCases") void leftRight(OSMWithTags way, OsmSpecifier spec, int expectedBackward, int expectedForward) { var result = spec.matchScores(way); assertEquals(expectedBackward, result.backward()); diff --git a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/ConditionTest.java b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/ConditionTest.java index a1d126003a5..def272652f6 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/ConditionTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/specifier/ConditionTest.java @@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.openstreetmap.model.OSMWithTags; import org.opentripplanner.openstreetmap.wayproperty.specifier.Condition.Absent; import org.opentripplanner.openstreetmap.wayproperty.specifier.Condition.Equals; @@ -34,7 +35,6 @@ import org.opentripplanner.openstreetmap.wayproperty.specifier.Condition.LessThan; import org.opentripplanner.openstreetmap.wayproperty.specifier.Condition.MatchResult; import org.opentripplanner.openstreetmap.wayproperty.specifier.Condition.Present; -import org.opentripplanner.test.support.VariableSource; class ConditionTest { @@ -56,18 +56,20 @@ class ConditionTest { ); static Condition noSidewalk = new Condition.EqualsAnyInOrAbsent("sidewalk"); - static Stream equalsCases = Stream.of( - Arguments.of(cyclewayLeft(), cyclewayLane, EXACT, NONE), - Arguments.of(cyclewayLaneTrack(), cyclewayLane, EXACT, NONE), - Arguments.of(cyclewayBoth(), cyclewayLane, EXACT, EXACT), - Arguments.of(cyclewayLaneTrack(), cyclewayTrack, NONE, EXACT), - Arguments.of(tramsForward(), embeddedTrams, NONE, EXACT) - ); + static Stream equalsCases() { + return Stream.of( + Arguments.of(cyclewayLeft(), cyclewayLane, EXACT, NONE), + Arguments.of(cyclewayLaneTrack(), cyclewayLane, EXACT, NONE), + Arguments.of(cyclewayBoth(), cyclewayLane, EXACT, EXACT), + Arguments.of(cyclewayLaneTrack(), cyclewayTrack, NONE, EXACT), + Arguments.of(tramsForward(), embeddedTrams, NONE, EXACT) + ); + } @ParameterizedTest( name = "way {0} with op {1} should have a backward result {2}, forward result {3}" ) - @VariableSource("equalsCases") + @MethodSource("equalsCases") void leftRight( OSMWithTags way, Condition op, @@ -78,32 +80,34 @@ void leftRight( assertEquals(forwardExpectation, op.matchForward(way)); } - static Stream otherCases = Stream.of( - Arguments.of(cycleway(), cyclewayPresent, WILDCARD), - Arguments.of(carTunnel(), cyclewayPresent, NONE), - Arguments.of(carTunnel(), cyclewayAbsent, EXACT), - Arguments.of(cobblestones(), cyclewayAbsent, EXACT), - Arguments.of(cycleway(), cyclewayAbsent, NONE), - Arguments.of(cycleway(), moreThanFourLanes, NONE), - Arguments.of(carTunnel(), moreThanFourLanes, NONE), - Arguments.of(pedestrianTunnel(), moreThanFourLanes, NONE), - Arguments.of(fiveLanes(), moreThanFourLanes, EXACT), - Arguments.of(fiveLanes(), lessThanFourLanes, NONE), - Arguments.of(threeLanes(), lessThanFourLanes, EXACT), - Arguments.of(carTunnel(), lessThanFourLanes, NONE), - Arguments.of(cycleway(), lessThanFourLanes, NONE), - Arguments.of(fiveLanes(), betweenFiveAndThreeLanes, EXACT), - Arguments.of(threeLanes(), betweenFiveAndThreeLanes, EXACT), - Arguments.of(veryBadSmoothness(), smoothnessBadAndWorseThanBad, EXACT), - Arguments.of(cobblestones(), smoothnessBadAndWorseThanBad, NONE), - Arguments.of(excellentSmoothness(), smoothnessBadAndWorseThanBad, NONE), - Arguments.of(noSidewalk(), noSidewalk, EXACT), - Arguments.of(highwayTertiary(), noSidewalk, EXACT), - Arguments.of(sidewalkBoth(), noSidewalk, NONE) - ); + static Stream otherCases() { + return Stream.of( + Arguments.of(cycleway(), cyclewayPresent, WILDCARD), + Arguments.of(carTunnel(), cyclewayPresent, NONE), + Arguments.of(carTunnel(), cyclewayAbsent, EXACT), + Arguments.of(cobblestones(), cyclewayAbsent, EXACT), + Arguments.of(cycleway(), cyclewayAbsent, NONE), + Arguments.of(cycleway(), moreThanFourLanes, NONE), + Arguments.of(carTunnel(), moreThanFourLanes, NONE), + Arguments.of(pedestrianTunnel(), moreThanFourLanes, NONE), + Arguments.of(fiveLanes(), moreThanFourLanes, EXACT), + Arguments.of(fiveLanes(), lessThanFourLanes, NONE), + Arguments.of(threeLanes(), lessThanFourLanes, EXACT), + Arguments.of(carTunnel(), lessThanFourLanes, NONE), + Arguments.of(cycleway(), lessThanFourLanes, NONE), + Arguments.of(fiveLanes(), betweenFiveAndThreeLanes, EXACT), + Arguments.of(threeLanes(), betweenFiveAndThreeLanes, EXACT), + Arguments.of(veryBadSmoothness(), smoothnessBadAndWorseThanBad, EXACT), + Arguments.of(cobblestones(), smoothnessBadAndWorseThanBad, NONE), + Arguments.of(excellentSmoothness(), smoothnessBadAndWorseThanBad, NONE), + Arguments.of(noSidewalk(), noSidewalk, EXACT), + Arguments.of(highwayTertiary(), noSidewalk, EXACT), + Arguments.of(sidewalkBoth(), noSidewalk, NONE) + ); + } @ParameterizedTest(name = "way {0} with op {1} should have a result {2}") - @VariableSource("otherCases") + @MethodSource("otherCases") void otherTests(OSMWithTags way, Condition op, MatchResult expectation) { assertEquals(expectation, op.match(way)); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDateTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDateTest.java index ecd75f5d273..dd9a2fffa66 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDateTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDateTest.java @@ -8,9 +8,9 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.model.Frequency; import org.opentripplanner.model.StopTime; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.network.Route; @@ -33,12 +33,14 @@ class TripPatternForDateTest { new Deduplicator() ); - static Stream testCases = Stream - .of(List.of(new FrequencyEntry(new Frequency(), tripTimes)), List.of()) - .map(Arguments::of); + static Stream testCases() { + return Stream + .of(List.of(new FrequencyEntry(new Frequency(), tripTimes)), List.of()) + .map(Arguments::of); + } @ParameterizedTest(name = "trip with frequencies {0} should be correctly filtered") - @VariableSource("testCases") + @MethodSource("testCases") void shouldExcludeAndIncludeBasedOnFrequency(List freqs) { var stopTime = new StopTime(); stopTime.setStop(STOP); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/WheelchairCostCalculatorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/WheelchairCostCalculatorTest.java index 0c2384ebabb..b7d3f255a9d 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/WheelchairCostCalculatorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/WheelchairCostCalculatorTest.java @@ -5,11 +5,11 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.raptor._data.transit.TestTripSchedule; import org.opentripplanner.raptor.api.model.RaptorTransferConstraint; import org.opentripplanner.raptor.spi.RaptorCostCalculator; import org.opentripplanner.routing.api.request.preference.AccessibilityPreferences; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model.basic.Accessibility; public class WheelchairCostCalculatorTest { @@ -34,14 +34,16 @@ public class WheelchairCostCalculatorTest { ); private final TestTripSchedule.Builder scheduleBuilder = TestTripSchedule.schedule("12:00 12:01"); - static Stream testCases = Stream.of( - Arguments.of(Accessibility.POSSIBLE, 0), - Arguments.of(Accessibility.NO_INFORMATION, UNKNOWN_ACCESSIBILITY_COST), - Arguments.of(Accessibility.NOT_POSSIBLE, INACCESSIBLE_TRIP_COST) - ); + static Stream testCases() { + return Stream.of( + Arguments.of(Accessibility.POSSIBLE, 0), + Arguments.of(Accessibility.NO_INFORMATION, UNKNOWN_ACCESSIBILITY_COST), + Arguments.of(Accessibility.NOT_POSSIBLE, INACCESSIBLE_TRIP_COST) + ); + } @ParameterizedTest(name = "accessibility of {0} should add an extra cost of {1}") - @VariableSource("testCases") + @MethodSource("testCases") public void calculateExtraBoardingCost(Accessibility wcb, int expectedExtraCost) { var schedule = scheduleBuilder.wheelchairBoarding(wcb).build(); 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 4823ea84300..be6266ccdbe 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 @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; import org.opentripplanner.framework.geometry.WgsCoordinate; @@ -25,7 +26,6 @@ import org.opentripplanner.routing.api.request.request.filter.SelectRequest; import org.opentripplanner.routing.api.request.request.filter.TransitFilter; import org.opentripplanner.routing.api.request.request.filter.TransitFilterRequest; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.basic.Accessibility; import org.opentripplanner.transit.model.basic.MainAndSubMode; @@ -70,14 +70,16 @@ class RouteRequestTransitDataProviderFilterTest { .withElevator(RELAXED_ACCESSIBILITY_PREFERENCE) .build(); - static Stream wheelchairCases = Stream.of( - Arguments.of(Accessibility.POSSIBLE, DEFAULT_ACCESSIBILITY), - Arguments.of(Accessibility.POSSIBLE, RELAXED_ACCESSIBILITY), - Arguments.of(Accessibility.NOT_POSSIBLE, DEFAULT_ACCESSIBILITY), - Arguments.of(Accessibility.NOT_POSSIBLE, RELAXED_ACCESSIBILITY), - Arguments.of(Accessibility.NO_INFORMATION, DEFAULT_ACCESSIBILITY), - Arguments.of(Accessibility.NO_INFORMATION, RELAXED_ACCESSIBILITY) - ); + static Stream wheelchairCases() { + return Stream.of( + Arguments.of(Accessibility.POSSIBLE, DEFAULT_ACCESSIBILITY), + Arguments.of(Accessibility.POSSIBLE, RELAXED_ACCESSIBILITY), + Arguments.of(Accessibility.NOT_POSSIBLE, DEFAULT_ACCESSIBILITY), + Arguments.of(Accessibility.NOT_POSSIBLE, RELAXED_ACCESSIBILITY), + Arguments.of(Accessibility.NO_INFORMATION, DEFAULT_ACCESSIBILITY), + Arguments.of(Accessibility.NO_INFORMATION, RELAXED_ACCESSIBILITY) + ); + } /** * Test filter for wheelchair access. @@ -85,7 +87,7 @@ class RouteRequestTransitDataProviderFilterTest { * @param wheelchair Accessibility for stops */ @ParameterizedTest - @VariableSource("wheelchairCases") + @MethodSource("wheelchairCases") void testWheelchairAccess(Accessibility wheelchair, WheelchairPreferences accessibility) { var firstStop = stopForTest("TEST:START", wheelchair, 0.0, 0.0); var lastStop = stopForTest("TEST:END", wheelchair, 0.0, 0.0); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java index 230097ebfc3..4283e5cca62 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java @@ -15,6 +15,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.framework.time.TimeUtils; import org.opentripplanner.model.transfer.TransferConstraint; import org.opentripplanner.raptor._data.RaptorTestConstants; @@ -28,7 +29,6 @@ import org.opentripplanner.raptor.api.path.TransitPathLeg; import org.opentripplanner.raptor.spi.DefaultSlackProvider; import org.opentripplanner.raptor.spi.RaptorSlackProvider; -import org.opentripplanner.test.support.VariableSource; public class TransferGeneratorTest implements RaptorTestConstants { @@ -497,24 +497,26 @@ void findTransferWithLongMinTimeTransfer() { // TODO: here we check that minimum transfer time and slack are NOT added up, but perhaps that is // asserting the wrong behaviour - static Stream minTransferTimeSlackCases = Stream.of( - // transfer takes 1 min plus 0 slack, passenger will make it - Arguments.of(ofMinutes(1), ofMinutes(0), true), - // slack is 30 minutes, passenger won't make the connection - Arguments.of(ofMinutes(1), ofMinutes(30), false), - // tight since 8 minutes slack + 1 min transfer time but still less than the 10 minutes required - Arguments.of(ofMinutes(1), ofMinutes(8), true), - // transfer slack is ignored since minimumTransferTime is short - Arguments.of(ofMinutes(1), ofMinutes(9), true), - Arguments.of(ofMinutes(11), ofMinutes(0), false), - Arguments.of(ofMinutes(9), ofMinutes(1), true), - Arguments.of(ofMinutes(0), ofMinutes(11), false) - ); + static Stream minTransferTimeSlackCases() { + return Stream.of( + // transfer takes 1 min plus 0 slack, passenger will make it + Arguments.of(ofMinutes(1), ofMinutes(0), true), + // slack is 30 minutes, passenger won't make the connection + Arguments.of(ofMinutes(1), ofMinutes(30), false), + // tight since 8 minutes slack + 1 min transfer time but still less than the 10 minutes required + Arguments.of(ofMinutes(1), ofMinutes(8), true), + // transfer slack is ignored since minimumTransferTime is short + Arguments.of(ofMinutes(1), ofMinutes(9), true), + Arguments.of(ofMinutes(11), ofMinutes(0), false), + Arguments.of(ofMinutes(9), ofMinutes(1), true), + Arguments.of(ofMinutes(0), ofMinutes(11), false) + ); + } @ParameterizedTest( name = "minimum transfer time of {0}, transfer slack of {1} should expectTransfer={2} on 10 min transfer window" ) - @VariableSource("minTransferTimeSlackCases") + @MethodSource("minTransferTimeSlackCases") void includeTransferSlackInMinimumTransferTime( Duration minTransferTime, Duration transferSlack, diff --git a/src/test/java/org/opentripplanner/routing/api/request/WheelchairPreferencesTest.java b/src/test/java/org/opentripplanner/routing/api/request/WheelchairPreferencesTest.java index 157235c4483..9dd533704c7 100644 --- a/src/test/java/org/opentripplanner/routing/api/request/WheelchairPreferencesTest.java +++ b/src/test/java/org/opentripplanner/routing/api/request/WheelchairPreferencesTest.java @@ -7,20 +7,22 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.preference.WheelchairPreferences; -import org.opentripplanner.test.support.VariableSource; class WheelchairPreferencesTest { - static Stream roundingTestCases = Stream.of( - Arguments.of(0.33333333333, 0.33, 0.333), - Arguments.of(0.77777777777, 0.78, 0.778) - ); + static Stream roundingTestCases() { + return Stream.of( + Arguments.of(0.33333333333, 0.33, 0.333), + Arguments.of(0.77777777777, 0.78, 0.778) + ); + } @ParameterizedTest( name = "Normalize value of {0} to rounded value {1} (maxSlope) and {2} (reluctance fields)" ) - @VariableSource("roundingTestCases") + @MethodSource("roundingTestCases") void testConstructorNormalization(double raw, double rounded2, double rounded3) { var roundedRequest = WheelchairPreferences .of() @@ -39,41 +41,43 @@ void testConstructorNormalization(double raw, double rounded2, double rounded3) assertEquals(roundedRequest.slopeExceededReluctance(), rounded2); } - static Stream toStringTestCases = Stream.of( - Arguments.of(DEFAULT, "WheelchairPreferences{}"), - Arguments.of( - WheelchairPreferences.of().withElevatorOnlyAccessible().build(), - "WheelchairPreferences{elevator: OnlyConsiderAccessible}" - ), - Arguments.of( - WheelchairPreferences.of().withTrip(DEFAULT_COSTS).build(), - "WheelchairPreferences{trip: AccessibilityPreferences{}}" - ), - Arguments.of( - WheelchairPreferences.of().withTrip(it -> it.withInaccessibleCost(100)).build(), - "WheelchairPreferences{trip: AccessibilityPreferences{inaccessibleCost: $100}}" - ), - Arguments.of( - WheelchairPreferences.of().withTripCost(99, 100).build(), - "WheelchairPreferences{trip: AccessibilityPreferences{unknownCost: $99, inaccessibleCost: $100}}" - ), - Arguments.of( - WheelchairPreferences - .of() - .withTripCost(10, 100) - .withStopCost(20, 200) - .withElevatorCost(30, 300) - .withInaccessibleStreetReluctance(1.0) - .withMaxSlope(0.123) - .withSlopeExceededReluctance(3) - .withStairsReluctance(4) - .build(), - "WheelchairPreferences{trip: AccessibilityPreferences{unknownCost: $10, inaccessibleCost: $100}, stop: AccessibilityPreferences{unknownCost: $20, inaccessibleCost: $200}, elevator: AccessibilityPreferences{unknownCost: $30, inaccessibleCost: $300}, inaccessibleStreetReluctance: 1.0, maxSlope: 0.123, slopeExceededReluctance: 3.0, stairsReluctance: 4.0}" - ) - ); + static Stream toStringTestCases() { + return Stream.of( + Arguments.of(DEFAULT, "WheelchairPreferences{}"), + Arguments.of( + WheelchairPreferences.of().withElevatorOnlyAccessible().build(), + "WheelchairPreferences{elevator: OnlyConsiderAccessible}" + ), + Arguments.of( + WheelchairPreferences.of().withTrip(DEFAULT_COSTS).build(), + "WheelchairPreferences{trip: AccessibilityPreferences{}}" + ), + Arguments.of( + WheelchairPreferences.of().withTrip(it -> it.withInaccessibleCost(100)).build(), + "WheelchairPreferences{trip: AccessibilityPreferences{inaccessibleCost: $100}}" + ), + Arguments.of( + WheelchairPreferences.of().withTripCost(99, 100).build(), + "WheelchairPreferences{trip: AccessibilityPreferences{unknownCost: $99, inaccessibleCost: $100}}" + ), + Arguments.of( + WheelchairPreferences + .of() + .withTripCost(10, 100) + .withStopCost(20, 200) + .withElevatorCost(30, 300) + .withInaccessibleStreetReluctance(1.0) + .withMaxSlope(0.123) + .withSlopeExceededReluctance(3) + .withStairsReluctance(4) + .build(), + "WheelchairPreferences{trip: AccessibilityPreferences{unknownCost: $10, inaccessibleCost: $100}, stop: AccessibilityPreferences{unknownCost: $20, inaccessibleCost: $200}, elevator: AccessibilityPreferences{unknownCost: $30, inaccessibleCost: $300}, inaccessibleStreetReluctance: 1.0, maxSlope: 0.123, slopeExceededReluctance: 3.0, stairsReluctance: 4.0}" + ) + ); + } @ParameterizedTest(name = "Verify toString() value is {1}") - @VariableSource("toStringTestCases") + @MethodSource("toStringTestCases") void testToString(WheelchairPreferences subject, String expected) { assertEquals(expected, subject.toString()); } diff --git a/src/test/java/org/opentripplanner/routing/api/request/framework/LinearFunctionSerializationTest.java b/src/test/java/org/opentripplanner/routing/api/request/framework/LinearFunctionSerializationTest.java index 9701fb412cc..e1785db61b1 100644 --- a/src/test/java/org/opentripplanner/routing/api/request/framework/LinearFunctionSerializationTest.java +++ b/src/test/java/org/opentripplanner/routing/api/request/framework/LinearFunctionSerializationTest.java @@ -11,9 +11,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.test.support.TestTableParser; -import org.opentripplanner.test.support.VariableSource; class LinearFunctionSerializationTest { @@ -21,25 +21,27 @@ class LinearFunctionSerializationTest { private static final Duration D1h = Duration.ofSeconds(3600); @SuppressWarnings("unused") - static Stream parseTestCases = TestTableParser.of( - """ - # INPUT || EXPECTED - # || CONSTANT | COEFFICIENT - 0+0t || 0s | 0.0 - 1+0.0111 t || 1s | 0.01 - 120 + 0.111 t || 2m | 0.11 - 120 + 0.111 t || 2m | 0.11 - 12.0 + 0 t || 12s | 0.0 - 2h3m + 1.111 t || 2h3m | 1.11 - 2h3m + 2.111 t || 2h3m | 2.1 - 3h + 5.111 t || 3h | 5.1 - 7m + 10.1 x || 7m | 10.0 - PT7s + 10.1 x || 7s | 10.0 - """ - ); + static Stream parseTestCases() { + return TestTableParser.of( + """ + # INPUT || EXPECTED + # || CONSTANT | COEFFICIENT + 0+0t || 0s | 0.0 + 1+0.0111 t || 1s | 0.01 + 120 + 0.111 t || 2m | 0.11 + 120 + 0.111 t || 2m | 0.11 + 12.0 + 0 t || 12s | 0.0 + 2h3m + 1.111 t || 2h3m | 1.11 + 2h3m + 2.111 t || 2h3m | 2.1 + 3h + 5.111 t || 3h | 5.1 + 7m + 10.1 x || 7m | 10.0 + PT7s + 10.1 x || 7s | 10.0 + """ + ); + } @ParameterizedTest - @VariableSource("parseTestCases") + @MethodSource("parseTestCases") void parseTest(String input, String expectedConstant, double expectedCoefficient) { Optional result = LinearFunctionSerialization.parse( input, diff --git a/src/test/java/org/opentripplanner/routing/api/request/preference/TimeSlopeSafetyTriangleTest.java b/src/test/java/org/opentripplanner/routing/api/request/preference/TimeSlopeSafetyTriangleTest.java index 7b2fe416290..2ba7f2569e4 100644 --- a/src/test/java/org/opentripplanner/routing/api/request/preference/TimeSlopeSafetyTriangleTest.java +++ b/src/test/java/org/opentripplanner/routing/api/request/preference/TimeSlopeSafetyTriangleTest.java @@ -7,26 +7,28 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; public class TimeSlopeSafetyTriangleTest { float DELTA = 0.001f; @SuppressWarnings("unused") - static Stream testCases = Stream.of( - // Input: time | slope | safety || Expected: time | slope | safety - Arguments.of(0.5, 0.3, 0.2, 0.5, 0.3, 0.2, "Exact"), - Arguments.of(1d, 1d, 1d, 0.33, 0.33, 0.34, "Greater than 1"), - Arguments.of(30d, 10d, 20d, 0.5, 0.17, 0.33, "Greater than 1 - big"), - Arguments.of(1d, 0d, 0d, 1d, 0d, 0d, "Two zeros"), - Arguments.of(0d, 0d, 0d, 0.33, 0.33, 0.34, "All zeros"), - Arguments.of(0.1, -1d, -1d, 1d, 0d, 0d, "Less than zero"), - Arguments.of(0d, 0.07, 0.93, 0d, 0.07, 0.93, "None precise round-off: " + (1.0 - 0.07)) - ); + static Stream testCases() { + return Stream.of( + // Input: time | slope | safety || Expected: time | slope | safety + Arguments.of(0.5, 0.3, 0.2, 0.5, 0.3, 0.2, "Exact"), + Arguments.of(1d, 1d, 1d, 0.33, 0.33, 0.34, "Greater than 1"), + Arguments.of(30d, 10d, 20d, 0.5, 0.17, 0.33, "Greater than 1 - big"), + Arguments.of(1d, 0d, 0d, 1d, 0d, 0d, "Two zeros"), + Arguments.of(0d, 0d, 0d, 0.33, 0.33, 0.34, "All zeros"), + Arguments.of(0.1, -1d, -1d, 1d, 0d, 0d, "Less than zero"), + Arguments.of(0d, 0.07, 0.93, 0d, 0.07, 0.93, "None precise round-off: " + (1.0 - 0.07)) + ); + } @ParameterizedTest(name = "Time/slope/safety: | {0} {1} {2} || {3} {4} {5} | {6}") - @VariableSource("testCases") + @MethodSource("testCases") public void test( double inTime, double inSlope, diff --git a/src/test/java/org/opentripplanner/routing/core/MoneyTest.java b/src/test/java/org/opentripplanner/routing/core/MoneyTest.java index 2323b396d5c..5f197708f1d 100644 --- a/src/test/java/org/opentripplanner/routing/core/MoneyTest.java +++ b/src/test/java/org/opentripplanner/routing/core/MoneyTest.java @@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.transit.model.basic.Money; class MoneyTest { @@ -27,36 +27,40 @@ class MoneyTest { private static final Money twoDollars = Money.usDollars(2); static Money threeEuroTwelve = Money.euros(3.12f); - static Stream testCases = Stream.of( - of(oneDollar, Locale.US, "$1.00"), - of(oneDollar, Locale.GERMANY, "1,00 $"), - of(Money.euros(1), Locale.GERMANY, "1,00 €"), - of(oneDollar, NORWEGIAN_BOKMAL, "USD 1,00"), - //of(oneDollar, NORWEGIAN_NYNORSK, "1.00 USD"), - of(hundredNOK, NORWEGIAN_BOKMAL, "kr 100,00") - //of(hundredNOK, NORWEGIAN_NYNORSK, "100.00 kr") - ); + static Stream testCases() { + return Stream.of( + of(oneDollar, Locale.US, "$1.00"), + of(oneDollar, Locale.GERMANY, "1,00 $"), + of(Money.euros(1), Locale.GERMANY, "1,00 €"), + of(oneDollar, NORWEGIAN_BOKMAL, "USD 1,00"), + //of(oneDollar, NORWEGIAN_NYNORSK, "1.00 USD"), + of(hundredNOK, NORWEGIAN_BOKMAL, "kr 100,00") + //of(hundredNOK, NORWEGIAN_NYNORSK, "100.00 kr") + ); + } @ParameterizedTest(name = "{0} with locale {1} should localise to \"{2}\"") - @VariableSource("testCases") + @MethodSource("testCases") void localize(Money money, Locale locale, String expected) { var localized = money.localize(locale); assertEquals(expected, localized); } - static Stream amountCases = Stream.of( - of(oneDollar, 1.0f), - of(threeEuroTwelve, 3.12f), - of(Money.euros(3.1f), 3.1f), - of(Money.euros(999.99f), 999.99f), - of(hundredNOK, 100.0f), - // Yen doesn't have fractional digits - of(yen(1000), 1000f), - of(yen(9999), 9999f) - ); + static Stream amountCases() { + return Stream.of( + of(oneDollar, 1.0f), + of(threeEuroTwelve, 3.12f), + of(Money.euros(3.1f), 3.1f), + of(Money.euros(999.99f), 999.99f), + of(hundredNOK, 100.0f), + // Yen doesn't have fractional digits + of(yen(1000), 1000f), + of(yen(9999), 9999f) + ); + } @ParameterizedTest - @VariableSource("amountCases") + @MethodSource("amountCases") void fractionalAmount(Money money, float expected) { var fractionalAmount = money.fractionalAmount(); assertEquals(expected, fractionalAmount.floatValue()); diff --git a/src/test/java/org/opentripplanner/standalone/config/routerequest/WheelchairConfigTest.java b/src/test/java/org/opentripplanner/standalone/config/routerequest/WheelchairConfigTest.java index 98b18f45d05..64216e5d83f 100644 --- a/src/test/java/org/opentripplanner/standalone/config/routerequest/WheelchairConfigTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/routerequest/WheelchairConfigTest.java @@ -11,59 +11,61 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.preference.AccessibilityPreferences; -import org.opentripplanner.test.support.VariableSource; class WheelchairConfigTest { - static Stream mapAccessibilityPreferencesTestCases = Stream.of( - Arguments.of( - "default ofOnlyAccessible()", - "{}", - ofOnlyAccessible(), - DEFAULT_COSTS, - ofOnlyAccessible() - ), - Arguments.of("default cost", "{}", ofCost(100, 200), ofCost(100, 200), ofCost(100, 200)), - Arguments.of( - "onlyConsiderAccessible with default costs", - "{\"onlyConsiderAccessible\": true}", - DEFAULT_COSTS, - DEFAULT_COSTS, - ofOnlyAccessible() - ), - Arguments.of( - "Default costs with default ofOnlyAccessible()", - "{\"onlyConsiderAccessible\": false}", - ofOnlyAccessible(), - DEFAULT_COSTS, - DEFAULT_COSTS - ), - Arguments.of( - "Only unknownCost set with default ofOnlyAccessible()", - "{\"unknownCost\": 100}", - ofOnlyAccessible(), - DEFAULT_COSTS, - ofCost(100, DEFAULT_COSTS.inaccessibleCost()) - ), - Arguments.of( - "Only inaccessibleCost set with default ofOnlyAccessible()", - "{\"inaccessibleCost\": 100}", - ofOnlyAccessible(), - DEFAULT_COSTS, - ofCost(DEFAULT_COSTS.unknownCost(), 100) - ), - Arguments.of( - "All values set", - "{\"unknownCost\": 200, \"inaccessibleCost\": 100, \"onlyConsiderAccessible\": false}", - ofOnlyAccessible(), - DEFAULT_COSTS, - ofCost(200, 100) - ) - ); + static Stream mapAccessibilityPreferencesTestCases() { + return Stream.of( + Arguments.of( + "default ofOnlyAccessible()", + "{}", + ofOnlyAccessible(), + DEFAULT_COSTS, + ofOnlyAccessible() + ), + Arguments.of("default cost", "{}", ofCost(100, 200), ofCost(100, 200), ofCost(100, 200)), + Arguments.of( + "onlyConsiderAccessible with default costs", + "{\"onlyConsiderAccessible\": true}", + DEFAULT_COSTS, + DEFAULT_COSTS, + ofOnlyAccessible() + ), + Arguments.of( + "Default costs with default ofOnlyAccessible()", + "{\"onlyConsiderAccessible\": false}", + ofOnlyAccessible(), + DEFAULT_COSTS, + DEFAULT_COSTS + ), + Arguments.of( + "Only unknownCost set with default ofOnlyAccessible()", + "{\"unknownCost\": 100}", + ofOnlyAccessible(), + DEFAULT_COSTS, + ofCost(100, DEFAULT_COSTS.inaccessibleCost()) + ), + Arguments.of( + "Only inaccessibleCost set with default ofOnlyAccessible()", + "{\"inaccessibleCost\": 100}", + ofOnlyAccessible(), + DEFAULT_COSTS, + ofCost(DEFAULT_COSTS.unknownCost(), 100) + ), + Arguments.of( + "All values set", + "{\"unknownCost\": 200, \"inaccessibleCost\": 100, \"onlyConsiderAccessible\": false}", + ofOnlyAccessible(), + DEFAULT_COSTS, + ofCost(200, 100) + ) + ); + } @ParameterizedTest(name = "{0}") - @VariableSource("mapAccessibilityPreferencesTestCases") + @MethodSource("mapAccessibilityPreferencesTestCases") void testMapAccessibilityPreferences( String name, String json, diff --git a/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java b/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java index 5adf8264d8e..ae19643db72 100644 --- a/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java +++ b/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java @@ -16,27 +16,29 @@ import org.jets3t.service.utils.Mimetypes; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.test.support.HttpForTest; -import org.opentripplanner.test.support.VariableSource; class EtagRequestFilterTest { static final String vectorTilesResponse = "some vector tiles"; static final String vectorTilesEtag = "\"20c17790\""; - static Stream etagCases = Stream.of( - Arguments.of("GET", 200, APPLICATION_X_PROTOBUF, bytes(vectorTilesResponse), vectorTilesEtag), - Arguments.of("GET", 404, APPLICATION_X_PROTOBUF, bytes("hello123"), null), - Arguments.of("GET", 200, "application/json", bytes("{}"), null), - Arguments.of("POST", 200, APPLICATION_X_PROTOBUF, bytes("hello123"), null), - Arguments.of("GET", 200, APPLICATION_X_PROTOBUF, bytes(""), null), - Arguments.of("POST", 200, Mimetypes.MIMETYPE_HTML, bytes(""), null) - ); + static Stream etagCases() { + return Stream.of( + Arguments.of("GET", 200, APPLICATION_X_PROTOBUF, bytes(vectorTilesResponse), vectorTilesEtag), + Arguments.of("GET", 404, APPLICATION_X_PROTOBUF, bytes("hello123"), null), + Arguments.of("GET", 200, "application/json", bytes("{}"), null), + Arguments.of("POST", 200, APPLICATION_X_PROTOBUF, bytes("hello123"), null), + Arguments.of("GET", 200, APPLICATION_X_PROTOBUF, bytes(""), null), + Arguments.of("POST", 200, Mimetypes.MIMETYPE_HTML, bytes(""), null) + ); + } @ParameterizedTest( name = "{0} request with response status={1} type={2}, entity={3} produces ETag header {4}" ) - @VariableSource("etagCases") + @MethodSource("etagCases") void writeEtag( String method, int status, @@ -56,13 +58,15 @@ void writeEtag( assertEquals(expectedEtag, response.getHeaderString(EtagRequestFilter.HEADER_ETAG)); } - static Stream ifNoneMatchCases = Stream.of( - Arguments.of("XXX", 200, bytes(vectorTilesResponse)), - Arguments.of(vectorTilesEtag, 304, null) - ); + static Stream ifNoneMatchCases() { + return Stream.of( + Arguments.of("XXX", 200, bytes(vectorTilesResponse)), + Arguments.of(vectorTilesEtag, 304, null) + ); + } @ParameterizedTest(name = "If-None-Match header of {0} should lead to a status code of {2}") - @VariableSource("ifNoneMatchCases") + @MethodSource("ifNoneMatchCases") void ifNoneMatch(String ifNoneMatch, int expectedStatus, byte[] expectedEntity) throws IOException { var request = HttpForTest.containerRequest("GET"); diff --git a/src/test/java/org/opentripplanner/standalone/server/RequestTraceFilterTest.java b/src/test/java/org/opentripplanner/standalone/server/RequestTraceFilterTest.java index 126ca887cc3..8198444f6be 100644 --- a/src/test/java/org/opentripplanner/standalone/server/RequestTraceFilterTest.java +++ b/src/test/java/org/opentripplanner/standalone/server/RequestTraceFilterTest.java @@ -7,7 +7,7 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.opentripplanner.test.support.VariableSource; +import org.junit.jupiter.params.provider.MethodSource; class RequestTraceFilterTest { @@ -19,22 +19,24 @@ class RequestTraceFilterTest { private static final String A_TOO_LONG_STRING = A_VERY_LONG_STRING + "1"; @SuppressWarnings("unused") - private static final Stream headerCheckTestCases = Stream.of( - Arguments.of(true, "ok"), - Arguments.of(true, "special characters: -_,;.:!#$%&/(){}[]=?+"), - Arguments.of(true, "quote: \"quoted\" 'single' `back` ´forward´"), - Arguments.of(true, "international characters: æøå öâò≈∰🧐"), - Arguments.of(true, A_VERY_LONG_STRING), - Arguments.of(false, A_TOO_LONG_STRING), - Arguments.of(false, "Vertical space new-line: -\n-"), - Arguments.of(false, "Vertical space return: -\r-"), - Arguments.of(false, "Vertical space form-feed: -\f-"), - Arguments.of(false, "Control character 0x01: -\u0001-"), - Arguments.of(false, "Control character 0x19: -\u0019-") - ); + private static final Stream headerCheckTestCases() { + return Stream.of( + Arguments.of(true, "ok"), + Arguments.of(true, "special characters: -_,;.:!#$%&/(){}[]=?+"), + Arguments.of(true, "quote: \"quoted\" 'single' `back` ´forward´"), + Arguments.of(true, "international characters: æøå öâò≈∰🧐"), + Arguments.of(true, A_VERY_LONG_STRING), + Arguments.of(false, A_TOO_LONG_STRING), + Arguments.of(false, "Vertical space new-line: -\n-"), + Arguments.of(false, "Vertical space return: -\r-"), + Arguments.of(false, "Vertical space form-feed: -\f-"), + Arguments.of(false, "Control character 0x01: -\u0001-"), + Arguments.of(false, "Control character 0x19: -\u0019-") + ); + } @ParameterizedTest - @VariableSource("headerCheckTestCases") + @MethodSource("headerCheckTestCases") void headerCheck(boolean expectedMatch, String input) { assertEquals( expectedMatch, diff --git a/src/test/java/org/opentripplanner/street/model/edge/ElevatorHopEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/ElevatorHopEdgeTest.java index 5d7c9d1213f..8efa6940d20 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/ElevatorHopEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/ElevatorHopEdgeTest.java @@ -8,13 +8,13 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.preference.AccessibilityPreferences; import org.opentripplanner.routing.api.request.preference.WheelchairPreferences; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model.basic.Accessibility; class ElevatorHopEdgeTest { @@ -22,12 +22,12 @@ class ElevatorHopEdgeTest { Vertex from = intersectionVertex(0, 0); Vertex to = intersectionVertex(1, 1); - static Stream noTraverse = Stream - .of(Accessibility.NO_INFORMATION, Accessibility.NOT_POSSIBLE) - .map(Arguments::of); + static Stream noTraverse() { + return Stream.of(Accessibility.NO_INFORMATION, Accessibility.NOT_POSSIBLE).map(Arguments::of); + } @ParameterizedTest(name = "{0} should be allowed to traverse when requesting onlyAccessible") - @VariableSource("noTraverse") + @MethodSource("noTraverse") void shouldNotTraverse(Accessibility wheelchair) { var req = StreetSearchRequest.of(); AccessibilityPreferences feature = AccessibilityPreferences.ofOnlyAccessible(); @@ -52,17 +52,19 @@ void shouldNotTraverse(Accessibility wheelchair) { assertTrue(State.isEmpty(result)); } - static Stream all = Stream.of( - // no extra cost - Arguments.of(Accessibility.POSSIBLE, 20), - // low extra cost - Arguments.of(Accessibility.NO_INFORMATION, 40), - // high extra cost - Arguments.of(Accessibility.NOT_POSSIBLE, 3620) - ); + static Stream all() { + return Stream.of( + // no extra cost + Arguments.of(Accessibility.POSSIBLE, 20), + // low extra cost + Arguments.of(Accessibility.NO_INFORMATION, 40), + // high extra cost + Arguments.of(Accessibility.NOT_POSSIBLE, 3620) + ); + } @ParameterizedTest(name = "{0} should allowed to traverse with a cost of {1}") - @VariableSource("all") + @MethodSource("all") void allowByDefault(Accessibility wheelchair, double expectedCost) { var req = StreetSearchRequest.of().build(); var result = traverse(wheelchair, req)[0]; diff --git a/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java index 1c7fdba7ae7..60859290646 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java @@ -7,22 +7,24 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.model.vertex.SimpleVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; -import org.opentripplanner.test.support.VariableSource; class EscalatorEdgeTest { Vertex from = new SimpleVertex("A", 10, 10); Vertex to = new SimpleVertex("B", 10.001, 10.001); - static Stream args = Stream.of(Arguments.of(1.5, 150), Arguments.of(3.0, 300)); + static Stream args() { + return Stream.of(Arguments.of(1.5, 150), Arguments.of(3.0, 300)); + } @ParameterizedTest(name = "escalatorReluctance of {0} should lead to traversal costs of {1}") - @VariableSource("args") + @MethodSource("args") void testWalking(double escalatorReluctance, double expectedWeight) { var edge = EscalatorEdge.createEscalatorEdge(from, to, 45); var req = StreetSearchRequest diff --git a/src/test/java/org/opentripplanner/street/model/edge/PathwayEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/PathwayEdgeTest.java index 9d4b1ff4fe2..6929f665938 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/PathwayEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/PathwayEdgeTest.java @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.routing.api.request.StreetMode; @@ -19,7 +20,6 @@ import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model.site.PathwayMode; class PathwayEdgeTest { @@ -141,20 +141,22 @@ void wheelchair() { assertEquals(300.0, state.getWeight()); } - static Stream slopeCases = Stream.of( - // no extra cost - Arguments.of(0.07, 120), - // no extra cost - Arguments.of(0.08, 120), - // 1 % above max - Arguments.of(0.09, 239), - // 1.1 % above the max slope, tiny extra cost - Arguments.of(0.091, 251), - // 1.15 % above the max slope, will incur larger cost - Arguments.of(0.0915, 257), - // 3 % above max slope, will incur very large cost - Arguments.of(0.11, 480) - ); + static Stream slopeCases() { + return Stream.of( + // no extra cost + Arguments.of(0.07, 120), + // no extra cost + Arguments.of(0.08, 120), + // 1 % above max + Arguments.of(0.09, 239), + // 1.1 % above the max slope, tiny extra cost + Arguments.of(0.091, 251), + // 1.15 % above the max slope, will incur larger cost + Arguments.of(0.0915, 257), + // 3 % above max slope, will incur very large cost + Arguments.of(0.11, 480) + ); + } /** * This makes sure that when you exceed the max slope in a wheelchair there isn't a hard cut-off @@ -164,7 +166,7 @@ void wheelchair() { * dramatically to the point where it's only used as a last resort. */ @ParameterizedTest(name = "slope of {0} should lead to traversal costs of {1}") - @VariableSource("slopeCases") + @MethodSource("slopeCases") void shouldScaleCostWithMaxSlope(double slope, long expectedCost) { var edge = PathwayEdge.createPathwayEdge( from, diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java index 2ecfa51822a..acd02653941 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeCostTest.java @@ -8,23 +8,25 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; -import org.opentripplanner.test.support.VariableSource; class StreetEdgeCostTest { - static Stream walkReluctanceCases = Stream.of( - Arguments.of(0.5, 37), - Arguments.of(1, 75), - Arguments.of(2, 150), - Arguments.of(3, 225) - ); + static Stream walkReluctanceCases() { + return Stream.of( + Arguments.of(0.5, 37), + Arguments.of(1, 75), + Arguments.of(2, 150), + Arguments.of(3, 225) + ); + } @ParameterizedTest(name = "walkRelucance of {0} should lead to traversal costs of {1}") - @VariableSource("walkReluctanceCases") + @MethodSource("walkReluctanceCases") public void walkReluctance(double walkReluctance, long expectedCost) { double length = 100; var edge = new StreetEdgeBuilder<>() @@ -45,15 +47,17 @@ public void walkReluctance(double walkReluctance, long expectedCost) { assertEquals(76, result.getElapsedTimeSeconds()); } - static Stream bikeReluctanceCases = Stream.of( - Arguments.of(0.5, 10), - Arguments.of(1, 20), - Arguments.of(2, 40), - Arguments.of(3, 60) - ); + static Stream bikeReluctanceCases() { + return Stream.of( + Arguments.of(0.5, 10), + Arguments.of(1, 20), + Arguments.of(2, 40), + Arguments.of(3, 60) + ); + } @ParameterizedTest(name = "bikeReluctance of {0} should lead to traversal costs of {1}") - @VariableSource("bikeReluctanceCases") + @MethodSource("bikeReluctanceCases") public void bikeReluctance(double bikeReluctance, long expectedCost) { double length = 100; var edge = new StreetEdgeBuilder<>() @@ -75,15 +79,17 @@ public void bikeReluctance(double bikeReluctance, long expectedCost) { assertEquals(20, result.getElapsedTimeSeconds()); } - static Stream carReluctanceCases = Stream.of( - Arguments.of(0.5, 4), - Arguments.of(1, 8), - Arguments.of(2, 17), - Arguments.of(3, 26) - ); + static Stream carReluctanceCases() { + return Stream.of( + Arguments.of(0.5, 4), + Arguments.of(1, 8), + Arguments.of(2, 17), + Arguments.of(3, 26) + ); + } @ParameterizedTest(name = "carReluctance of {0} should lead to traversal costs of {1}") - @VariableSource("carReluctanceCases") + @MethodSource("carReluctanceCases") public void carReluctance(double carReluctance, long expectedCost) { double length = 100; var edge = new StreetEdgeBuilder<>() @@ -105,14 +111,12 @@ public void carReluctance(double carReluctance, long expectedCost) { assertEquals(9, result.getElapsedTimeSeconds()); } - static Stream stairsCases = Stream.of( - Arguments.of(1, 22), - Arguments.of(1.5, 33), - Arguments.of(3, 67) - ); + static Stream stairsCases() { + return Stream.of(Arguments.of(1, 22), Arguments.of(1.5, 33), Arguments.of(3, 67)); + } @ParameterizedTest(name = "stairs reluctance of {0} should lead to traversal costs of {1}") - @VariableSource("stairsCases") + @MethodSource("stairsCases") public void stairsReluctance(double stairsReluctance, long expectedCost) { double length = 10; var stairsEdge = new StreetEdgeBuilder<>() @@ -138,14 +142,12 @@ public void stairsReluctance(double stairsReluctance, long expectedCost) { assertEquals(15, (long) notStairsResult.weight); } - static Stream bikeStairsCases = Stream.of( - Arguments.of(1, 45), - Arguments.of(1.5, 67), - Arguments.of(3, 135) - ); + static Stream bikeStairsCases() { + return Stream.of(Arguments.of(1, 45), Arguments.of(1.5, 67), Arguments.of(3, 135)); + } @ParameterizedTest(name = "bike stairs reluctance of {0} should lead to traversal costs of {1}") - @VariableSource("bikeStairsCases") + @MethodSource("bikeStairsCases") public void bikeStairsReluctance(double stairsReluctance, long expectedCost) { double length = 10; var stairsEdge = new StreetEdgeBuilder<>() @@ -173,14 +175,12 @@ public void bikeStairsReluctance(double stairsReluctance, long expectedCost) { assertEquals(37, (long) notStairsResult.weight); } - static Stream walkSafetyCases = Stream.of( - Arguments.of(0, 15), - Arguments.of(0.5, 22), - Arguments.of(1, 30) - ); + static Stream walkSafetyCases() { + return Stream.of(Arguments.of(0, 15), Arguments.of(0.5, 22), Arguments.of(1, 30)); + } @ParameterizedTest(name = "walk safety factor of {0} should lead to traversal costs of {1}") - @VariableSource("walkSafetyCases") + @MethodSource("walkSafetyCases") public void walkSafetyFactor(double walkSafetyFactor, long expectedCost) { double length = 10; var safeEdge = new StreetEdgeBuilder<>() diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeRentalTraversalTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeRentalTraversalTest.java index 20682b6048b..44de661f327 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeRentalTraversalTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeRentalTraversalTest.java @@ -17,6 +17,7 @@ import javax.annotation.Nonnull; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.model.RentalFormFactor; import org.opentripplanner.street.model.StreetTraversalPermission; @@ -24,7 +25,6 @@ import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; import org.opentripplanner.street.search.state.StateEditor; -import org.opentripplanner.test.support.VariableSource; public class StreetEdgeRentalTraversalTest { @@ -42,18 +42,20 @@ private static Stream baseCases(StreetTraversalPermission p) { ); } - static Stream allowedToTraverse = Stream - .of( - StreetTraversalPermission.ALL, - StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE, - StreetTraversalPermission.BICYCLE - ) - .flatMap(StreetEdgeRentalTraversalTest::baseCases); + static Stream allowedToTraverse() { + return Stream + .of( + StreetTraversalPermission.ALL, + StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE, + StreetTraversalPermission.BICYCLE + ) + .flatMap(StreetEdgeRentalTraversalTest::baseCases); + } @ParameterizedTest( name = "Form factor {0}, street mode {1} should be able to traverse edge with permission {2}" ) - @VariableSource("allowedToTraverse") + @MethodSource("allowedToTraverse") void scooterBicycleTraversal( RentalFormFactor formFactor, StreetMode streetMode, @@ -74,14 +76,16 @@ void scooterBicycleTraversal( assertEquals(formFactor.traverseMode, afterTraversal.currentMode()); } - static Stream noTraversal = Stream - .of(StreetTraversalPermission.CAR, StreetTraversalPermission.NONE) - .flatMap(StreetEdgeRentalTraversalTest::baseCases); + static Stream noTraversal() { + return Stream + .of(StreetTraversalPermission.CAR, StreetTraversalPermission.NONE) + .flatMap(StreetEdgeRentalTraversalTest::baseCases); + } @ParameterizedTest( name = "Form factor {0}, street mode {1} should not be able to traverse edge with permission {2}" ) - @VariableSource("noTraversal") + @MethodSource("noTraversal") void noTraversal( RentalFormFactor formFactor, StreetMode streetMode, diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java index ed4b92da779..7c2767a6935 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeWheelchairCostTest.java @@ -7,6 +7,7 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.impl.PackedCoordinateSequence; import org.opentripplanner.routing.api.request.preference.WheelchairPreferences; @@ -14,7 +15,6 @@ import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; -import org.opentripplanner.test.support.VariableSource; class StreetEdgeWheelchairCostTest { @@ -26,26 +26,28 @@ public StreetEdgeWheelchairCostTest() { V2 = intersectionVertex("V2", 2.0, 0.0); } - static Stream slopeCases = Stream.of( - // no extra cost - Arguments.of(0.07, 1, 5081), - // no extra cost - Arguments.of(0.08, 1, 5945), - // no extra cost - Arguments.of(0.09, 1, 6908), - // 0.1 % above the max slope, tiny extra cost - Arguments.of(0.091, 1, 7708), - // 3 % above max slope, will incur very large cost - Arguments.of(0.091, 3, 9110), - // 0.1 % above the max slope, but high reluctance will large cost - Arguments.of(0.0915, 1, 8116), - // 2 % above max slope, but lowered reluctance - Arguments.of(0.11, 0.5, 17649), - // 2 % above max slope, will incur very large cost - Arguments.of(0.11, 1, 26474), - // 3 % above max slope, will incur very large cost - Arguments.of(0.12, 1, 37978) - ); + static Stream slopeCases() { + return Stream.of( + // no extra cost + Arguments.of(0.07, 1, 5081), + // no extra cost + Arguments.of(0.08, 1, 5945), + // no extra cost + Arguments.of(0.09, 1, 6908), + // 0.1 % above the max slope, tiny extra cost + Arguments.of(0.091, 1, 7708), + // 3 % above max slope, will incur very large cost + Arguments.of(0.091, 3, 9110), + // 0.1 % above the max slope, but high reluctance will large cost + Arguments.of(0.0915, 1, 8116), + // 2 % above max slope, but lowered reluctance + Arguments.of(0.11, 0.5, 17649), + // 2 % above max slope, will incur very large cost + Arguments.of(0.11, 1, 26474), + // 3 % above max slope, will incur very large cost + Arguments.of(0.12, 1, 37978) + ); + } /** * This makes sure that when you exceed the max slope in a wheelchair there isn't a hard cut-off @@ -57,7 +59,7 @@ public StreetEdgeWheelchairCostTest() { @ParameterizedTest( name = "slope of {0} with maxSlopeExceededReluctance of {1} should lead to traversal costs of {2}" ) - @VariableSource("slopeCases") + @MethodSource("slopeCases") public void shouldScaleCostWithMaxSlope(double slope, double reluctance, long expectedCost) { double length = 1000; var edge = new StreetEdgeBuilder<>() @@ -104,16 +106,14 @@ public void shouldScaleCostWithMaxSlope(double slope, double reluctance, long ex assertEquals(expectedCost, (long) result.weight); } - static Stream wheelchairStairsCases = Stream.of( - Arguments.of(1, 22), - Arguments.of(10, 225), - Arguments.of(100, 2255) - ); + static Stream wheelchairStairsCases() { + return Stream.of(Arguments.of(1, 22), Arguments.of(10, 225), Arguments.of(100, 2255)); + } @ParameterizedTest( name = "wheelchair stairs reluctance of {0} should lead to traversal costs of {1}" ) - @VariableSource("wheelchairStairsCases") + @MethodSource("wheelchairStairsCases") public void wheelchairStairsReluctance(double stairsReluctance, long expectedCost) { double length = 10; var stairEdge = new StreetEdgeBuilder<>() @@ -153,16 +153,14 @@ public void wheelchairStairsReluctance(double stairsReluctance, long expectedCos assertEquals(7, (long) notStairsResult.weight); } - static Stream inaccessibleStreetCases = Stream.of( - Arguments.of(1f, 15), - Arguments.of(10f, 150), - Arguments.of(100f, 1503) - ); + static Stream inaccessibleStreetCases() { + return Stream.of(Arguments.of(1f, 15), Arguments.of(10f, 150), Arguments.of(100f, 1503)); + } @ParameterizedTest( name = "an inaccessible street with the reluctance of {0} should lead to traversal costs of {1}" ) - @VariableSource("inaccessibleStreetCases") + @MethodSource("inaccessibleStreetCases") public void inaccessibleStreet(float inaccessibleStreetReluctance, long expectedCost) { double length = 10; var edge = new StreetEdgeBuilder<>() @@ -201,17 +199,19 @@ public void inaccessibleStreet(float inaccessibleStreetReluctance, long expected assertEquals(15, (long) accessibleResult.weight); } - static Stream walkReluctanceCases = Stream.of( - Arguments.of(0.5, 3), - Arguments.of(1, 7), - Arguments.of(10, 75), - Arguments.of(100, 751) - ); + static Stream walkReluctanceCases() { + return Stream.of( + Arguments.of(0.5, 3), + Arguments.of(1, 7), + Arguments.of(10, 75), + Arguments.of(100, 751) + ); + } @ParameterizedTest( name = "walkReluctance of {0} should affect wheelchair users and lead to traversal costs of {1}" ) - @VariableSource("walkReluctanceCases") + @MethodSource("walkReluctanceCases") public void walkReluctance(double walkReluctance, long expectedCost) { double length = 10; var edge = new StreetEdgeBuilder<>() diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java index a2a052d3b5c..99de720a5a2 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java @@ -11,6 +11,7 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.routing.api.request.StreetMode; @@ -20,22 +21,23 @@ import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; -import org.opentripplanner.test.support.VariableSource; class StreetVehicleParkingLinkTest { - static Stream testCases = Stream.of( - of(Set.of(), Set.of(), Set.of(), true), - of(Set.of("a-tag"), Set.of(), Set.of(), true), - of(Set.of("a"), Set.of("a"), Set.of(), false), - of(Set.of("a"), Set.of("a"), Set.of("a"), false), - of(Set.of("a", "b"), Set.of("b"), Set.of("a"), false), - of(Set.of("a", "b"), Set.of(), Set.of("a"), true), - of(Set.of("a", "b"), Set.of(), Set.of("c"), false) - ); + static Stream testCases() { + return Stream.of( + of(Set.of(), Set.of(), Set.of(), true), + of(Set.of("a-tag"), Set.of(), Set.of(), true), + of(Set.of("a"), Set.of("a"), Set.of(), false), + of(Set.of("a"), Set.of("a"), Set.of("a"), false), + of(Set.of("a", "b"), Set.of("b"), Set.of("a"), false), + of(Set.of("a", "b"), Set.of(), Set.of("a"), true), + of(Set.of("a", "b"), Set.of(), Set.of("c"), false) + ); + } @ParameterizedTest(name = "Parking[tags={0}], Request[not={1}, select={2}] should traverse={3}") - @VariableSource("testCases") + @MethodSource("testCases") void foo(Set parkingTags, Set not, Set select, boolean shouldTraverse) { var streetVertex = intersectionVertex(1, 1); var parking = VehicleParking diff --git a/src/test/java/org/opentripplanner/street/search/state/StateDataTest.java b/src/test/java/org/opentripplanner/street/search/state/StateDataTest.java index 1138fd6cf02..83cec24cd77 100644 --- a/src/test/java/org/opentripplanner/street/search/state/StateDataTest.java +++ b/src/test/java/org/opentripplanner/street/search/state/StateDataTest.java @@ -6,18 +6,20 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.search.request.StreetSearchRequest; -import org.opentripplanner.test.support.VariableSource; class StateDataTest { - static Stream cases = Arrays - .stream(StreetMode.values()) - .flatMap(mode -> Stream.of(Arguments.of(true, mode), Arguments.of(false, mode))); + static Stream cases() { + return Arrays + .stream(StreetMode.values()) + .flatMap(mode -> Stream.of(Arguments.of(true, mode), Arguments.of(false, mode))); + } @ParameterizedTest(name = "arriveBy={0}, streetMode={1}") - @VariableSource("cases") + @MethodSource("cases") void baseCases(boolean arriveBy, StreetMode streetMode) { var req = StreetSearchRequest.of().withArriveBy(arriveBy).withMode(streetMode).build(); var data = StateData.getBaseCaseStateData(req); diff --git a/src/test/java/org/opentripplanner/street/search/state/StateTest.java b/src/test/java/org/opentripplanner/street/search/state/StateTest.java index 34d3af11b68..9722f1dd785 100644 --- a/src/test/java/org/opentripplanner/street/search/state/StateTest.java +++ b/src/test/java/org/opentripplanner/street/search/state/StateTest.java @@ -31,11 +31,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.request.StreetSearchRequest; -import org.opentripplanner.test.support.VariableSource; class StateTest { @@ -48,30 +48,32 @@ class StateTest { NULL_RENTAL_STATES.add(null); } - static Stream testCases = Stream.of( - of(SCOOTER_RENTAL, false, Set.of(BEFORE_RENTING), Set.of(WALK)), - //FIXME: it's strange that the arriveBy rental searches all start on a bicycle - of(SCOOTER_RENTAL, true, Set.of(HAVE_RENTED, RENTING_FLOATING), Set.of(WALK, BICYCLE)), - of(BIKE_RENTAL, false, Set.of(BEFORE_RENTING), Set.of(WALK)), - of(BIKE_RENTAL, true, Set.of(HAVE_RENTED, RENTING_FLOATING), Set.of(WALK, BICYCLE)), - of(CAR_RENTAL, false, Set.of(BEFORE_RENTING), Set.of(WALK)), - of(CAR_RENTAL, true, Set.of(HAVE_RENTED, RENTING_FLOATING), Set.of(WALK, BICYCLE)), - of(StreetMode.CAR, false, NULL_RENTAL_STATES, Set.of(CAR)), - of(BIKE, false, NULL_RENTAL_STATES, Set.of(BICYCLE)), - of(StreetMode.WALK, false, NULL_RENTAL_STATES, Set.of(TraverseMode.WALK)), - of(BIKE_TO_PARK, false, NULL_RENTAL_STATES, Set.of(BICYCLE)), - of(CAR_TO_PARK, false, NULL_RENTAL_STATES, Set.of(CAR)), - of(FLEXIBLE, false, NULL_RENTAL_STATES, Set.of(WALK)), - of(CAR_PICKUP, false, NULL_RENTAL_STATES, Set.of(CAR, WALK)), - of(CAR_PICKUP, true, NULL_RENTAL_STATES, Set.of(CAR, WALK)), - of(CAR_HAILING, false, NULL_RENTAL_STATES, Set.of(CAR, WALK)), - of(CAR_HAILING, true, NULL_RENTAL_STATES, Set.of(CAR, WALK)) - ); + static Stream testCases() { + return Stream.of( + of(SCOOTER_RENTAL, false, Set.of(BEFORE_RENTING), Set.of(WALK)), + //FIXME: it's strange that the arriveBy rental searches all start on a bicycle + of(SCOOTER_RENTAL, true, Set.of(HAVE_RENTED, RENTING_FLOATING), Set.of(WALK, BICYCLE)), + of(BIKE_RENTAL, false, Set.of(BEFORE_RENTING), Set.of(WALK)), + of(BIKE_RENTAL, true, Set.of(HAVE_RENTED, RENTING_FLOATING), Set.of(WALK, BICYCLE)), + of(CAR_RENTAL, false, Set.of(BEFORE_RENTING), Set.of(WALK)), + of(CAR_RENTAL, true, Set.of(HAVE_RENTED, RENTING_FLOATING), Set.of(WALK, BICYCLE)), + of(StreetMode.CAR, false, NULL_RENTAL_STATES, Set.of(CAR)), + of(BIKE, false, NULL_RENTAL_STATES, Set.of(BICYCLE)), + of(StreetMode.WALK, false, NULL_RENTAL_STATES, Set.of(TraverseMode.WALK)), + of(BIKE_TO_PARK, false, NULL_RENTAL_STATES, Set.of(BICYCLE)), + of(CAR_TO_PARK, false, NULL_RENTAL_STATES, Set.of(CAR)), + of(FLEXIBLE, false, NULL_RENTAL_STATES, Set.of(WALK)), + of(CAR_PICKUP, false, NULL_RENTAL_STATES, Set.of(CAR, WALK)), + of(CAR_PICKUP, true, NULL_RENTAL_STATES, Set.of(CAR, WALK)), + of(CAR_HAILING, false, NULL_RENTAL_STATES, Set.of(CAR, WALK)), + of(CAR_HAILING, true, NULL_RENTAL_STATES, Set.of(CAR, WALK)) + ); + } @ParameterizedTest( name = "street mode {0}, arriveBy={1} should lead to initial states with rentalStates={2}, currentModes={3}" ) - @VariableSource("testCases") + @MethodSource("testCases") void initialStates( StreetMode streetMode, boolean arriveBy, diff --git a/src/test/java/org/opentripplanner/test/support/VariableArgumentsProvider.java b/src/test/java/org/opentripplanner/test/support/VariableArgumentsProvider.java deleted file mode 100644 index 1ae9fb2af84..00000000000 --- a/src/test/java/org/opentripplanner/test/support/VariableArgumentsProvider.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.opentripplanner.test.support; - -import java.lang.reflect.Field; -import java.util.stream.Stream; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.support.AnnotationConsumer; - -/** - * This annotation processor allows you to provide a variable as the input for a JUnit {@link - * org.junit.jupiter.params.ParameterizedTest}. - * - * Check the usages of {@link VariableSource} to see examples for how to use. - */ -class VariableArgumentsProvider implements ArgumentsProvider, AnnotationConsumer { - - private String variableName; - - @Override - public Stream provideArguments(ExtensionContext context) { - return context - .getTestClass() - .map(this::getField) - .map(this::getValue) - .orElseThrow(() -> new IllegalArgumentException("Failed to load test arguments")); - } - - @Override - public void accept(VariableSource variableSource) { - variableName = variableSource.value(); - } - - private Field getField(Class clazz) { - try { - return clazz.getDeclaredField(variableName); - } catch (Exception e) { - return null; - } - } - - @SuppressWarnings("unchecked") - private Stream getValue(Field field) { - Object value = null; - var accessible = field.isAccessible(); - try { - field.setAccessible(true); - value = field.get(null); - } catch (Exception ignored) {} - - field.setAccessible(accessible); - - return value == null ? null : (Stream) value; - } -} diff --git a/src/test/java/org/opentripplanner/test/support/VariableSource.java b/src/test/java/org/opentripplanner/test/support/VariableSource.java deleted file mode 100644 index 254110cf6d2..00000000000 --- a/src/test/java/org/opentripplanner/test/support/VariableSource.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.opentripplanner.test.support; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import org.junit.jupiter.params.provider.ArgumentsSource; - -@Documented -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@ArgumentsSource(VariableArgumentsProvider.class) -public @interface VariableSource { - /** - * The name of the static variable - */ - String value(); -} diff --git a/src/test/java/org/opentripplanner/updater/trip/TimetableSnapshotSourceTest.java b/src/test/java/org/opentripplanner/updater/trip/TimetableSnapshotSourceTest.java index d25de6ff021..8c28290de66 100644 --- a/src/test/java/org/opentripplanner/updater/trip/TimetableSnapshotSourceTest.java +++ b/src/test/java/org/opentripplanner/updater/trip/TimetableSnapshotSourceTest.java @@ -33,6 +33,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.ConstantsForTests; import org.opentripplanner.TestOtpModel; import org.opentripplanner.framework.i18n.NonLocalizedString; @@ -40,7 +41,6 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.Timetable; import org.opentripplanner.model.TimetableSnapshot; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.TripPattern; @@ -1090,16 +1090,18 @@ SameAssert not() { } } - static Stream purgeExpiredDataTestCases = Stream.of( - // purgeExpiredData maxSnapshotFrequency || snapshots PatternSnapshotA PatternSnapshotB - Arguments.of(Boolean.TRUE, -1, NotSame, NotSame), - Arguments.of(Boolean.FALSE, -1, NotSame, Same), - Arguments.of(Boolean.TRUE, 1000, NotSame, NotSame), - Arguments.of(Boolean.FALSE, 1000, Same, Same) - ); + static Stream purgeExpiredDataTestCases() { + return Stream.of( + // purgeExpiredData maxSnapshotFrequency || snapshots PatternSnapshotA PatternSnapshotB + Arguments.of(Boolean.TRUE, -1, NotSame, NotSame), + Arguments.of(Boolean.FALSE, -1, NotSame, Same), + Arguments.of(Boolean.TRUE, 1000, NotSame, NotSame), + Arguments.of(Boolean.FALSE, 1000, Same, Same) + ); + } @ParameterizedTest(name = "purgeExpired: {0}, maxFrequency: {1} || {2} {3}") - @VariableSource("purgeExpiredDataTestCases") + @MethodSource("purgeExpiredDataTestCases") public void testPurgeExpiredData( boolean purgeExpiredData, int maxSnapshotFrequency, diff --git a/src/test/java/org/opentripplanner/updater/vehicle_position/RealtimeVehicleMatcherTest.java b/src/test/java/org/opentripplanner/updater/vehicle_position/RealtimeVehicleMatcherTest.java index 29d03844260..ea5d86cd0e1 100644 --- a/src/test/java/org/opentripplanner/updater/vehicle_position/RealtimeVehicleMatcherTest.java +++ b/src/test/java/org/opentripplanner/updater/vehicle_position/RealtimeVehicleMatcherTest.java @@ -23,12 +23,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.model.StopTime; import org.opentripplanner.service.realtimevehicles.internal.DefaultRealtimeVehicleService; import org.opentripplanner.standalone.config.routerconfig.updaters.VehiclePositionsUpdaterConfig; -import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.framework.FeedScopedId; @@ -326,14 +326,16 @@ public void clearOldTrips() { assertEquals(0, service.getRealtimeVehicles(pattern2).size()); } - static Stream inferenceTestCases = Stream.of( - Arguments.of("2022-04-05T15:26:04+02:00", "2022-04-05"), - Arguments.of("2022-04-06T00:26:04+02:00", "2022-04-05"), - Arguments.of("2022-04-06T10:26:04+02:00", "2022-04-06") - ); + static Stream inferenceTestCases() { + return Stream.of( + Arguments.of("2022-04-05T15:26:04+02:00", "2022-04-05"), + Arguments.of("2022-04-06T00:26:04+02:00", "2022-04-05"), + Arguments.of("2022-04-06T10:26:04+02:00", "2022-04-06") + ); + } @ParameterizedTest(name = "{0} should resolve to {1}") - @VariableSource("inferenceTestCases") + @MethodSource("inferenceTestCases") void inferServiceDayOfTripAt6(String time, String expectedDate) { var trip = TransitModelForTest.trip(tripId).build(); From d54db3b65dfffa4fbcf8c1b37c05f2a162795c21 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 4 Mar 2024 15:03:16 +0100 Subject: [PATCH 167/183] Apply suggestions from code review Co-authored-by: Vincent Paturet <46598384+vpaturet@users.noreply.github.com> --- .../raptor/api/model/RaptorAccessEgress.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java b/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java index aac389b7af4..3a7f48cf743 100644 --- a/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java +++ b/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java @@ -54,8 +54,8 @@ public interface RaptorAccessEgress { *

* For example, for Park&Ride, driving all the way to the * destination is very often the best option when looking at the time criteria. When an - * increasing time-penalty is applied to access/egress with driving then driving less become - * more favorable. This also improves performance, since we usually add a very high cost to + * increasing time-penalty is applied to a car access/egress, then driving become less + * favorable. This also improves performance, since we usually add a very high cost to * driving - making all park&ride access legs optimal - forcing Raptor to compute a path for * every option. The short drives are optimal on cost, and the long are optimal on time. In the * case of park&ride the time-penalty enables Raptor to choose one of the shortest access/egress @@ -64,8 +64,8 @@ public interface RaptorAccessEgress { * Another example is FLEX, where we in many use-cases want regular transit to win if there is * an offer. Only in the case where the FLEX is the only solution we want it to be presented. * To achieve this, we must add an extra duration to the time of the FLEX access/egress - it does - * not help to just edd extra cost - witch makes both FLEX optimal on time and transit optimal on - * cost. Many optimal access paths have an inpact on performance as vell. + * not help to just add extra cost - which makes both FLEX optimal on time and transit optimal on + * cost. Keeping a large number of optimal access paths has a negative impact on performance as well. *

* * The unit is seconds and the default value is {@link RaptorConstants#TIME_NOT_SET}. From cacec850aa1f6d4fe0dbf5f1a7cd9786a9fc2750 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 4 Mar 2024 15:05:26 +0100 Subject: [PATCH 168/183] Apply suggestions from code review Co-authored-by: Vincent Paturet <46598384+vpaturet@users.noreply.github.com> --- src/main/java/org/opentripplanner/raptor/path/Path.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/raptor/path/Path.java b/src/main/java/org/opentripplanner/raptor/path/Path.java index 15fcf7b34e7..ebade8b2690 100644 --- a/src/main/java/org/opentripplanner/raptor/path/Path.java +++ b/src/main/java/org/opentripplanner/raptor/path/Path.java @@ -19,9 +19,9 @@ import org.opentripplanner.raptor.api.path.TransitPathLeg; /** - * The result of a Raptor search is a path describing the one possible journey. The path is then + * The result of a Raptor search is a path describing the one possible journey. The path is the * main DTO part of the Raptor result, but it is also used internally in Raptor. Hence, it is a bit - * more complex, and it has more responsiblilites than it should. + * more complex, and it has more responsiblilities than it should. *

* To improve the design, Raptor should not use the path internally. Instead, there should * be a special destination arrival that could take over the Raptor responsibilities. The From cd76862ebe81ad33867cfdb2704836f61314d784 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Mon, 4 Mar 2024 14:06:38 +0000 Subject: [PATCH 169/183] Add changelog entry for #5705 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 0b6134e4939..1f86690f7ee 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -97,6 +97,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Use NeTEx authority short name if name is not present [#5698](https://github.com/opentripplanner/OpenTripPlanner/pull/5698) - Add Hamburg OSM mapper [#5701](https://github.com/opentripplanner/OpenTripPlanner/pull/5701) - Remove configurable car speed and determine it in graph build [#5657](https://github.com/opentripplanner/OpenTripPlanner/pull/5657) +- Avoid cumulative real-time updates [#5705](https://github.com/opentripplanner/OpenTripPlanner/pull/5705) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From 573ae93cd62d2a57cf4be92c94dad84fd035f5ad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 01:21:43 +0000 Subject: [PATCH 170/183] fix(deps): update dependency ch.qos.logback:logback-classic to v1.5.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8764dc0578a..a3d2763039c 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 1.12.2 5.5.3 - 1.5.2 + 1.5.3 9.9.1 2.0.12 2.0.15 From 1fc6f5c95078afef0b293f60b8e675e708f6a808 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 01:21:49 +0000 Subject: [PATCH 171/183] chore(deps): update dependency io.github.git-commit-id:git-commit-id-maven-plugin to v8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a3d2763039c..ddc19f4528b 100644 --- a/pom.xml +++ b/pom.xml @@ -321,7 +321,7 @@ but we need the Maven project version as well, so we perform substitution. --> io.github.git-commit-id git-commit-id-maven-plugin - 7.0.0 + 8.0.0 From bfb7c37a49a122bfcd6e2cfc82cc8cfbdd46444a Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Tue, 5 Mar 2024 10:49:28 +0000 Subject: [PATCH 172/183] Add changelog entry for #5715 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 1f86690f7ee..9e2e515c463 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -98,6 +98,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Add Hamburg OSM mapper [#5701](https://github.com/opentripplanner/OpenTripPlanner/pull/5701) - Remove configurable car speed and determine it in graph build [#5657](https://github.com/opentripplanner/OpenTripPlanner/pull/5657) - Avoid cumulative real-time updates [#5705](https://github.com/opentripplanner/OpenTripPlanner/pull/5705) +- Fix time penalty [#5715](https://github.com/opentripplanner/OpenTripPlanner/pull/5715) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From 6fc4f608a8f710d68d56c3febafe16f6932cf532 Mon Sep 17 00:00:00 2001 From: OTP Serialization Version Bot Date: Tue, 5 Mar 2024 10:49:51 +0000 Subject: [PATCH 173/183] Bump serialization version id for #5715 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ddc19f4528b..f809bae08c6 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ - 147 + 148 30.2 2.51 From ed2c083c48ad917b8ca3da1073e352881cb34a65 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 5 Mar 2024 12:41:42 +0100 Subject: [PATCH 174/183] Revert back to using CONFIG icon [ci skip] --- src/main/java/org/opentripplanner/datastore/OtpDataStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/datastore/OtpDataStore.java b/src/main/java/org/opentripplanner/datastore/OtpDataStore.java index 0c2e9a6608c..937b4fb8203 100644 --- a/src/main/java/org/opentripplanner/datastore/OtpDataStore.java +++ b/src/main/java/org/opentripplanner/datastore/OtpDataStore.java @@ -108,7 +108,7 @@ public void open() { if (config.stopConsolidation() != null) { stopConsolidation = - findSourceUsingAllRepos(it -> it.findCompositeSource(config.stopConsolidation(), GTFS)); + findSourceUsingAllRepos(it -> it.findCompositeSource(config.stopConsolidation(), CONFIG)); } addAll(Arrays.asList(streetGraph, graph, buildReportDir)); From 0e9c32869dba575fe1e30aee51640eb200610d43 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 5 Mar 2024 13:02:10 +0100 Subject: [PATCH 175/183] Fix finding of stop consolidation file [ci skip] --- src/main/java/org/opentripplanner/datastore/OtpDataStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/datastore/OtpDataStore.java b/src/main/java/org/opentripplanner/datastore/OtpDataStore.java index 937b4fb8203..397d3f64c70 100644 --- a/src/main/java/org/opentripplanner/datastore/OtpDataStore.java +++ b/src/main/java/org/opentripplanner/datastore/OtpDataStore.java @@ -108,7 +108,7 @@ public void open() { if (config.stopConsolidation() != null) { stopConsolidation = - findSourceUsingAllRepos(it -> it.findCompositeSource(config.stopConsolidation(), CONFIG)); + findSingleSource(config.stopConsolidation(), config.stopConsolidation().toString(), GTFS); } addAll(Arrays.asList(streetGraph, graph, buildReportDir)); From 4cdd8be12443cc134f2285d64fb5636ce10cf585 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 5 Mar 2024 16:04:06 +0100 Subject: [PATCH 176/183] Update logback-classic only once a month [ci skip] --- renovate.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/renovate.json5 b/renovate.json5 index e2a94318313..29e51863384 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -44,7 +44,8 @@ // gbfs-java-model patch releases are automatic dependency upgrades so we automerge { "matchPackageNames": [ - "org.entur.gbfs:gbfs-java-model" + "org.entur.gbfs:gbfs-java-model", + "ch.qos.logback:logback-classic" ], "matchUpdateTypes": ["patch"], "schedule": "on the 18th day of the month", @@ -104,7 +105,6 @@ "org.apache.maven.plugins:maven-surefire-plugin", "org.jacoco:jacoco-maven-plugin", // coverage plugin "org.apache.commons:commons-compress", // only used by tests - "ch.qos.logback:logback-classic", // maven plugins "org.codehaus.mojo:build-helper-maven-plugin", "org.apache.maven.plugins:maven-gpg-plugin", From 5e0b927ea7e4906a80ae61772950d2b8cdc4af9c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 01:41:50 +0000 Subject: [PATCH 177/183] chore(deps): update micrometer.version to v1.12.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f809bae08c6..97697b6896f 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.16.1 3.1.5 5.10.2 - 1.12.2 + 1.12.3 5.5.3 1.5.3 9.9.1 From b9aa5b16ad9a7d90f5b3ad1cf77c67d8a57e687f Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 7 Mar 2024 14:20:41 +0100 Subject: [PATCH 178/183] fix: Access without time-penalty is removed when access with exits. --- .../rangeraptor/transit/AccessPaths.java | 2 +- .../rangeraptor/transit/AccessPathsTest.java | 36 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java index d070a804f9c..66b7227584d 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java @@ -194,7 +194,7 @@ private List filterOnTimePenaltyLimitIfExist(List e.timePenalty() > iterationTimePenaltyLimit).toList(); } return list; diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java index bf8e06a73d7..5b4c0c89bc2 100644 --- a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java +++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java @@ -83,7 +83,7 @@ void calculateMaxNumberOfRides() { } @Test - void iterateOverPathsWithPenalty() { + void iterateOverPathsWithTimePenalty() { // Expected at departure 540 var flexFastWithPenalty = FLEX_FAST.withTimePenalty(60); @@ -146,7 +146,7 @@ void iterateOverPathsWithPenalty() { } @Test - void iterateOverPathsWithPenaltyInReversDirection() { + void iterateOverPathsWithTimePenaltyInReversDirection() { // Expected at departure 540 var flexFastWithPenalty = FLEX_FAST.withTimePenalty(60); @@ -164,6 +164,10 @@ void iterateOverPathsWithPenaltyInReversDirection() { REVERSE ); + // Make sure standard iterator works + expect(accessPaths.arrivedOnStreetByNumOfRides(0), WALK_B, walkFastWithPenalty); + expect(accessPaths.arrivedOnBoardByNumOfRides(3), FLEX_B, flexFastWithPenalty); + var iterator = accessPaths.iterateOverPathsWithPenalty(600); // First iteration @@ -196,6 +200,34 @@ void iterateOverPathsWithPenaltyInReversDirection() { assertFalse(iterator.hasNext()); } + @Test + void testRegularIteratorsAndIteratorWithPenaltyWorksTogether() { + var walkFastWithPenalty = WALK_FAST.withTimePenalty(60); + + // Without time-penalty, the iterator should be empty + var accessPaths = AccessPaths.create( + 60, + List.of(walkFastWithPenalty, WALK_COST), + MULTI_CRITERIA, + FORWARD + ); + + // Both accesses are expected before with enter the "time-penalty" iteration + expect(accessPaths.arrivedOnStreetByNumOfRides(0), WALK_COST, walkFastWithPenalty); + expect(accessPaths.arrivedOnBoardByNumOfRides(0)); + + var iterator = accessPaths.iterateOverPathsWithPenalty(600); + + // First iteration - only access with time-penalty is expected + assertTrue(iterator.hasNext()); + assertEquals(540, iterator.next()); + expect(accessPaths.arrivedOnStreetByNumOfRides(0), walkFastWithPenalty); + expect(accessPaths.arrivedOnBoardByNumOfRides(0)); + + // Second iteration - Done + assertFalse(iterator.hasNext()); + } + @Test void hasTimeDependentAccess() { var accessPaths = AccessPaths.create( From c82b91e7b86a635d57dd05c87e40c685ecf767cb Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 7 Mar 2024 14:26:04 +0100 Subject: [PATCH 179/183] Revert "fix: Access without time-penalty is removed when access with exits." This reverts commit b9aa5b16ad9a7d90f5b3ad1cf77c67d8a57e687f. --- .../rangeraptor/transit/AccessPaths.java | 2 +- .../rangeraptor/transit/AccessPathsTest.java | 36 ++----------------- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java index 66b7227584d..d070a804f9c 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java @@ -194,7 +194,7 @@ private List filterOnTimePenaltyLimitIfExist(List e.timePenalty() > iterationTimePenaltyLimit).toList(); } return list; diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java index 5b4c0c89bc2..bf8e06a73d7 100644 --- a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java +++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java @@ -83,7 +83,7 @@ void calculateMaxNumberOfRides() { } @Test - void iterateOverPathsWithTimePenalty() { + void iterateOverPathsWithPenalty() { // Expected at departure 540 var flexFastWithPenalty = FLEX_FAST.withTimePenalty(60); @@ -146,7 +146,7 @@ void iterateOverPathsWithTimePenalty() { } @Test - void iterateOverPathsWithTimePenaltyInReversDirection() { + void iterateOverPathsWithPenaltyInReversDirection() { // Expected at departure 540 var flexFastWithPenalty = FLEX_FAST.withTimePenalty(60); @@ -164,10 +164,6 @@ void iterateOverPathsWithTimePenaltyInReversDirection() { REVERSE ); - // Make sure standard iterator works - expect(accessPaths.arrivedOnStreetByNumOfRides(0), WALK_B, walkFastWithPenalty); - expect(accessPaths.arrivedOnBoardByNumOfRides(3), FLEX_B, flexFastWithPenalty); - var iterator = accessPaths.iterateOverPathsWithPenalty(600); // First iteration @@ -200,34 +196,6 @@ void iterateOverPathsWithTimePenaltyInReversDirection() { assertFalse(iterator.hasNext()); } - @Test - void testRegularIteratorsAndIteratorWithPenaltyWorksTogether() { - var walkFastWithPenalty = WALK_FAST.withTimePenalty(60); - - // Without time-penalty, the iterator should be empty - var accessPaths = AccessPaths.create( - 60, - List.of(walkFastWithPenalty, WALK_COST), - MULTI_CRITERIA, - FORWARD - ); - - // Both accesses are expected before with enter the "time-penalty" iteration - expect(accessPaths.arrivedOnStreetByNumOfRides(0), WALK_COST, walkFastWithPenalty); - expect(accessPaths.arrivedOnBoardByNumOfRides(0)); - - var iterator = accessPaths.iterateOverPathsWithPenalty(600); - - // First iteration - only access with time-penalty is expected - assertTrue(iterator.hasNext()); - assertEquals(540, iterator.next()); - expect(accessPaths.arrivedOnStreetByNumOfRides(0), walkFastWithPenalty); - expect(accessPaths.arrivedOnBoardByNumOfRides(0)); - - // Second iteration - Done - assertFalse(iterator.hasNext()); - } - @Test void hasTimeDependentAccess() { var accessPaths = AccessPaths.create( From 87b2108bb8aee4ab9bcb1388553b3cefc0db3283 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 7 Mar 2024 14:20:41 +0100 Subject: [PATCH 180/183] fix: Access without time-penalty is removed when access with exits. --- .../rangeraptor/transit/AccessPaths.java | 2 +- .../rangeraptor/transit/AccessPathsTest.java | 55 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java index d070a804f9c..66b7227584d 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java @@ -194,7 +194,7 @@ private List filterOnTimePenaltyLimitIfExist(List e.timePenalty() > iterationTimePenaltyLimit).toList(); } return list; diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java index bf8e06a73d7..8611a046a5b 100644 --- a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java +++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPathsTest.java @@ -83,7 +83,7 @@ void calculateMaxNumberOfRides() { } @Test - void iterateOverPathsWithPenalty() { + void iterateOverPathsWithTimePenalty() { // Expected at departure 540 var flexFastWithPenalty = FLEX_FAST.withTimePenalty(60); @@ -113,6 +113,25 @@ void iterateOverPathsWithPenalty() { FORWARD ); + // Make sure standard iterator works + expect( + accessPaths.arrivedOnStreetByNumOfRides(0), + WALK_B, + walkFastWithPenalty, + walkCostWithPenalty + ); + expect(accessPaths.arrivedOnBoardByNumOfRides(1)); + expect(accessPaths.arrivedOnStreetByNumOfRides(1)); + expect(accessPaths.arrivedOnBoardByNumOfRides(2), flexTxWithPenalty); + expect(accessPaths.arrivedOnStreetByNumOfRides(2), FLEX_WALK_B); + expect( + accessPaths.arrivedOnBoardByNumOfRides(3), + FLEX_B, + flexFastWithPenalty, + flexCostWithPenalty + ); + expect(accessPaths.arrivedOnStreetByNumOfRides(3)); + var iterator = accessPaths.iterateOverPathsWithPenalty(600); // First iteration @@ -146,7 +165,7 @@ void iterateOverPathsWithPenalty() { } @Test - void iterateOverPathsWithPenaltyInReversDirection() { + void iterateOverPathsWithTimePenaltyInReversDirection() { // Expected at departure 540 var flexFastWithPenalty = FLEX_FAST.withTimePenalty(60); @@ -164,6 +183,10 @@ void iterateOverPathsWithPenaltyInReversDirection() { REVERSE ); + // Make sure standard iterator works + expect(accessPaths.arrivedOnStreetByNumOfRides(0), WALK_B, walkFastWithPenalty); + expect(accessPaths.arrivedOnBoardByNumOfRides(3), FLEX_B, flexFastWithPenalty); + var iterator = accessPaths.iterateOverPathsWithPenalty(600); // First iteration @@ -196,6 +219,34 @@ void iterateOverPathsWithPenaltyInReversDirection() { assertFalse(iterator.hasNext()); } + @Test + void testRegularIteratorsAndIteratorWithPenaltyWorksTogether() { + var walkFastWithPenalty = WALK_FAST.withTimePenalty(60); + + // Without time-penalty, the iterator should be empty + var accessPaths = AccessPaths.create( + 60, + List.of(walkFastWithPenalty, WALK_COST), + MULTI_CRITERIA, + FORWARD + ); + + // Both accesses are expected before with enter the "time-penalty" iteration + expect(accessPaths.arrivedOnStreetByNumOfRides(0), WALK_COST, walkFastWithPenalty); + expect(accessPaths.arrivedOnBoardByNumOfRides(0)); + + var iterator = accessPaths.iterateOverPathsWithPenalty(600); + + // First iteration - only access with time-penalty is expected + assertTrue(iterator.hasNext()); + assertEquals(540, iterator.next()); + expect(accessPaths.arrivedOnStreetByNumOfRides(0), walkFastWithPenalty); + expect(accessPaths.arrivedOnBoardByNumOfRides(0)); + + // Second iteration - Done + assertFalse(iterator.hasNext()); + } + @Test void hasTimeDependentAccess() { var accessPaths = AccessPaths.create( From 3934161330b392b7263bc610c65920e7a03cc9ff Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:43:13 +0000 Subject: [PATCH 181/183] fix(deps): update dependency org.glassfish.jaxb:jaxb-runtime to v4.0.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 97697b6896f..3248cfede87 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ 2.0.12 2.0.15 1.26 - 4.0.4 + 4.0.5 UTF-8 opentripplanner/OpenTripPlanner From 70f6fe40f4058e4c1d728c4bebfa685b2a4f70a5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 7 Mar 2024 18:31:11 +0100 Subject: [PATCH 182/183] Don't update Azure dependency [ci skip] --- renovate.json5 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json5 b/renovate.json5 index 29e51863384..8ecbbeb565e 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -25,7 +25,8 @@ "com.microsoft.azure:azure-servicebus", "com.azure.resourcemanager:azure-resourcemanager-servicebus", "com.azure:azure-core", - "com.azure:azure-messaging-servicebus" + "com.azure:azure-messaging-servicebus", + "com.azure:azure-identity" ], "enabled": false }, From 961f49967c9ac615c11a17eff7cf99282744ec32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 23:26:46 +0000 Subject: [PATCH 183/183] fix(deps): update dependency com.google.cloud:libraries-bom to v26.34.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 97697b6896f..1df69006218 100644 --- a/pom.xml +++ b/pom.xml @@ -545,7 +545,7 @@ com.google.cloud libraries-bom - 26.31.0 + 26.34.0 pom import