From 6d5be573ea5e88713a19c3551f6470890601f913 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:40:25 +0200 Subject: [PATCH 01/83] Add ISO date times to GraphQL API --- .../apis/gtfs/GraphQLScalars.java | 32 +++++++++++++++++++ .../apis/gtfs/datafetchers/LegImpl.java | 13 ++++++++ .../gtfs/generated/GraphQLDataFetchers.java | 4 +++ .../apis/gtfs/generated/graphql-codegen.yml | 1 + .../opentripplanner/apis/gtfs/schema.graphqls | 5 +++ .../apis/gtfs/queries/plan-extended.graphql | 2 ++ 6 files changed, 57 insertions(+) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 6280ac28ac2..0e21df48dc1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -10,6 +10,10 @@ import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import javax.annotation.Nonnull; import org.locationtech.jts.geom.Geometry; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.graphql.scalar.DurationScalarFactory; @@ -50,6 +54,34 @@ public String parseLiteral(Object input) { ) .build(); + public static GraphQLScalarType dateTimeScalar = GraphQLScalarType + .newScalar() + .name("DateTime") + .coercing( + new Coercing() { + @Override + public String serialize(@Nonnull Object dataFetcherResult) + throws CoercingSerializeException { + if (dataFetcherResult instanceof ZonedDateTime zdt) { + return zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } else if (dataFetcherResult instanceof OffsetDateTime odt) { + return odt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } else return null; + } + + @Override + public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { + return null; + } + + @Override + public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { + return null; + } + } + ) + .build(); + public static GraphQLScalarType geoJsonScalar = GraphQLScalarType .newScalar() .name("GeoJson") diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 639cb95bf28..94cda56b652 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -2,6 +2,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -78,6 +79,12 @@ public DataFetcher duration() { } @Override + public DataFetcher end() { + return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + } + + @Override + @Deprecated public DataFetcher endTime() { return environment -> getSource(environment).getEndTime().toInstant().toEpochMilli(); } @@ -216,6 +223,12 @@ public DataFetcher serviceDate() { } @Override + public DataFetcher start() { + return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + } + + @Override + @Deprecated public DataFetcher startTime() { return environment -> getSource(environment).getStartTime().toInstant().toEpochMilli(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 2f39f7f4030..8194a0c5f4f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -440,6 +440,8 @@ public interface GraphQLLeg { public DataFetcher duration(); + public DataFetcher end(); + public DataFetcher endTime(); public DataFetcher> fareProducts(); @@ -480,6 +482,8 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); + public DataFetcher start(); + public DataFetcher startTime(); public DataFetcher> steps(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index c141266d2e6..24cde3afe43 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -26,6 +26,7 @@ config: Polyline: String GeoJson: org.locationtech.jts.geom.Geometry Grams: org.opentripplanner.framework.model.Grams + DateTime: java.time.OffsetDateTime Duration: java.time.Duration mappers: AbsoluteDirection: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLAbsoluteDirection#GraphQLAbsoluteDirection diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index daeb57d655e..2576dcf6441 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1640,12 +1640,17 @@ type RideHailingEstimate { productName: String } +scalar DateTime + type Leg { """ The date and time when this leg begins. Format: Unix timestamp in milliseconds. """ startTime: Long + start: DateTime + end: DateTime + """ The date and time when this leg ends. Format: Unix timestamp in milliseconds. """ diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index db30d8489ef..7eb4552b63d 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -28,6 +28,8 @@ walkTime legs { mode + start + end from { name lat From 67cf67ee842e2bdccc787e957563575d1fe4352d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:40:36 +0200 Subject: [PATCH 02/83] Add scalar --- .../java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index ff3e8681ce8..5ddfb2ba6d1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -111,6 +111,7 @@ protected static GraphQLSchema buildSchema() { .scalar(GraphQLScalars.geoJsonScalar) .scalar(GraphQLScalars.graphQLIDScalar) .scalar(GraphQLScalars.gramsScalar) + .scalar(GraphQLScalars.dateTimeScalar) .scalar(ExtendedScalars.GraphQLLong) .type("Node", type -> type.typeResolver(new NodeTypeResolver())) .type("PlaceInterface", type -> type.typeResolver(new PlaceInterfaceTypeResolver())) From 5835324d8e9226e007e8cfc28e13c462b94be843 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:51:37 +0200 Subject: [PATCH 03/83] Implement start/end for Itinerary --- .../apis/gtfs/datafetchers/ItineraryImpl.java | 12 ++++++++++++ .../apis/gtfs/generated/GraphQLDataFetchers.java | 4 +++- .../org/opentripplanner/apis/gtfs/schema.graphqls | 9 ++++++--- .../apis/gtfs/expectations/plan-extended.json | 10 ++++++++++ .../apis/gtfs/queries/plan-extended.graphql | 3 +++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java index c7ae82a2355..5396f66024f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java @@ -2,6 +2,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; import java.util.List; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.mapping.NumberMapper; @@ -32,6 +33,11 @@ public DataFetcher elevationLost() { return environment -> getSource(environment).getElevationLost(); } + @Override + public DataFetcher end() { + return environment -> getSource(environment).endTime().toOffsetDateTime(); + } + @Override public DataFetcher endTime() { return environment -> getSource(environment).endTime().toInstant().toEpochMilli(); @@ -57,6 +63,12 @@ public DataFetcher numberOfTransfers() { return environment -> getSource(environment).getNumberOfTransfers(); } + @Override + public DataFetcher start() { + return environment -> getSource(environment).startTime().toOffsetDateTime(); + } + + @Override public DataFetcher startTime() { return environment -> getSource(environment).startTime().toInstant().toEpochMilli(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 8194a0c5f4f..87ab5ad7b1d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -398,7 +398,7 @@ public interface GraphQLItinerary { public DataFetcher elevationLost(); - public DataFetcher emissionsPerPerson(); + public DataFetcher end(); public DataFetcher endTime(); @@ -408,6 +408,8 @@ public interface GraphQLItinerary { public DataFetcher> legs(); + public DataFetcher start(); + public DataFetcher numberOfTransfers(); public DataFetcher startTime(); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2576dcf6441..d77b63a0956 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1500,12 +1500,15 @@ type Itinerary { """ Time when the user leaves from the origin. Format: Unix timestamp in milliseconds. """ - startTime: Long + startTime: Long @deprecated(reason: "Use `start` instead which includes timezone information.") """ - Time when the user arrives to the destination.. Format: Unix timestamp in milliseconds. + Time when the user arrives to the destination. Format: Unix timestamp in milliseconds. """ - endTime: Long + endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") + + start: DateTime + end: DateTime """Duration of the trip on this itinerary, in seconds.""" duration: Long diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 557cdec8659..378e87838e9 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -3,6 +3,8 @@ "plan" : { "itineraries" : [ { + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T12:00:00Z", "startTime" : 1580641200000, "endTime" : 1580644800000, "generalizedCost" : 4072, @@ -16,6 +18,8 @@ "legs" : [ { "mode" : "WALK", + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T11:00:00Z", "from" : { "name" : "A", "lat" : 5.0, @@ -41,6 +45,8 @@ }, { "mode" : "BUS", + "start" : "2020-02-02T11:01:00Z", + "end" : "2020-02-02T11:01:00Z", "from" : { "name" : "B", "lat" : 6.0, @@ -68,6 +74,8 @@ }, { "mode" : "RAIL", + "start" : "2020-02-02T11:30:00Z", + "end" : "2020-02-02T11:30:00Z", "from" : { "name" : "C", "lat" : 7.0, @@ -115,6 +123,8 @@ }, { "mode" : "CAR", + "start" : "2020-02-02T11:50:00Z", + "end" : "2020-02-02T11:50:00Z", "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index 7eb4552b63d..cde918e43b0 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -16,6 +16,9 @@ } ]) { itineraries { + start + end + # next two are deprecated startTime endTime generalizedCost From 8a966c2fd44cd478ac8f071dbe5a8b8d25850d5e Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:54:02 +0200 Subject: [PATCH 04/83] Use correct times for leg --- .../apis/gtfs/datafetchers/LegImpl.java | 2 +- .../apis/gtfs/expectations/plan-extended.json | 8 ++++---- .../apis/gtfs/expectations/plan.json | 20 +++++++++---------- .../apis/gtfs/queries/plan.graphql | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 94cda56b652..50e935ce7ea 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -80,7 +80,7 @@ public DataFetcher duration() { @Override public DataFetcher end() { - return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + return environment -> getSource(environment).getEndTime().toOffsetDateTime(); } @Override diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 378e87838e9..739e0453e08 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -19,7 +19,7 @@ { "mode" : "WALK", "start" : "2020-02-02T11:00:00Z", - "end" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T11:00:20Z", "from" : { "name" : "A", "lat" : 5.0, @@ -46,7 +46,7 @@ { "mode" : "BUS", "start" : "2020-02-02T11:01:00Z", - "end" : "2020-02-02T11:01:00Z", + "end" : "2020-02-02T11:15:00Z", "from" : { "name" : "B", "lat" : 6.0, @@ -75,7 +75,7 @@ { "mode" : "RAIL", "start" : "2020-02-02T11:30:00Z", - "end" : "2020-02-02T11:30:00Z", + "end" : "2020-02-02T11:50:00Z", "from" : { "name" : "C", "lat" : 7.0, @@ -124,7 +124,7 @@ { "mode" : "CAR", "start" : "2020-02-02T11:50:00Z", - "end" : "2020-02-02T11:50:00Z", + "end" : "2020-02-02T12:00:00Z", "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 06fd20be150..408b1c17ed5 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -3,13 +3,13 @@ "plan" : { "itineraries" : [ { - "startTime" : 1580641200000, - "endTime" : 1580644800000, + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T12:00:00Z", "legs" : [ { "mode" : "WALK", - "startTime" : 1580641200000, - "endTime" : 1580641220000, + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T11:00:20Z", "from" : { "name" : "A", "lat" : 5.0, @@ -29,8 +29,8 @@ }, { "mode" : "BUS", - "startTime" : 1580641260000, - "endTime" : 1580642100000, + "start" : "2020-02-02T11:01:00Z", + "end" : "2020-02-02T11:15:00Z", "from" : { "name" : "B", "lat" : 6.0, @@ -56,8 +56,8 @@ }, { "mode" : "RAIL", - "startTime" : 1580643000000, - "endTime" : 1580644200000, + "start" : "2020-02-02T11:30:00Z", + "end" : "2020-02-02T11:50:00Z", "from" : { "name" : "C", "lat" : 7.0, @@ -83,8 +83,8 @@ }, { "mode" : "CAR", - "startTime" : 1580644200000, - "endTime" : 1580644800000, + "start" : "2020-02-02T11:50:00Z", + "end" : "2020-02-02T12:00:00Z", "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index d71c991234d..4e638d93759 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -17,12 +17,12 @@ }, ]) { itineraries { - startTime - endTime + start + end legs { mode - startTime - endTime + start + end from { name lat From ed766e651d5a9b602ea9ca053850dad4c1ddbc59 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 13:25:27 +0200 Subject: [PATCH 05/83] Add iso time to Place --- docs/apis/GraphQL-Tutorial.md | 16 +++---- .../apis/gtfs/datafetchers/ItineraryImpl.java | 3 +- .../apis/gtfs/datafetchers/PlaceImpl.java | 13 ++++++ .../gtfs/generated/GraphQLDataFetchers.java | 4 ++ .../opentripplanner/apis/gtfs/schema.graphqls | 43 +++++++++++-------- .../apis/gtfs/expectations/plan.json | 32 +++++++------- .../apis/gtfs/queries/plan.graphql | 8 ++-- 7 files changed, 72 insertions(+), 47 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 8df6d6f38ee..480e2ef10ee 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -88,25 +88,25 @@ Most people want to get routing results out of OTP, so lets see the query for th }, ]) { itineraries { - startTime - endTime + start + end legs { mode - startTime - endTime + start + end from { name lat lon - departureTime - arrivalTime + departure + arrival } to { name lat lon - departureTime - arrivalTime + departure + arrival } route { gtfsId diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java index 5396f66024f..20d5a9c348d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java @@ -38,6 +38,7 @@ public DataFetcher end() { return environment -> getSource(environment).endTime().toOffsetDateTime(); } + @Deprecated @Override public DataFetcher endTime() { return environment -> getSource(environment).endTime().toInstant().toEpochMilli(); @@ -68,7 +69,7 @@ public DataFetcher start() { return environment -> getSource(environment).startTime().toOffsetDateTime(); } - + @Deprecated @Override public DataFetcher startTime() { return environment -> getSource(environment).startTime().toInstant().toEpochMilli(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index ce3ca0986b1..28cd088cf86 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -2,6 +2,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLVertexType; import org.opentripplanner.apis.gtfs.model.StopPosition; @@ -17,6 +18,12 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { + @Override + public DataFetcher arrival() { + return environment -> getSource(environment).arrival.toOffsetDateTime(); + } + + @Deprecated @Override public DataFetcher arrivalTime() { return environment -> getSource(environment).arrival.toInstant().toEpochMilli(); @@ -45,6 +52,12 @@ public DataFetcher carPark() { return this::getCarPark; } + @Deprecated + @Override + public DataFetcher departure() { + return environment -> getSource(environment).departure.toOffsetDateTime(); + } + @Override public DataFetcher departureTime() { return environment -> getSource(environment).departure.toInstant().toEpochMilli(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 87ab5ad7b1d..431cf874152 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -582,6 +582,8 @@ public interface GraphQLPattern { } public interface GraphQLPlace { + public DataFetcher arrival(); + public DataFetcher arrivalTime(); public DataFetcher bikePark(); @@ -590,6 +592,8 @@ public interface GraphQLPlace { public DataFetcher carPark(); + public DataFetcher departure(); + public DataFetcher departureTime(); public DataFetcher lat(); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index d77b63a0956..f6abf30aacb 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1646,19 +1646,9 @@ type RideHailingEstimate { scalar DateTime type Leg { - """ - The date and time when this leg begins. Format: Unix timestamp in milliseconds. - """ - startTime: Long - start: DateTime end: DateTime - """ - The date and time when this leg ends. Format: Unix timestamp in milliseconds. - """ - endTime: Long - """ For transit leg, the offset from the scheduled departure time of the boarding stop in this leg, i.e. scheduled time of departure at boarding stop = @@ -1833,6 +1823,17 @@ type Leg { that applies to multiple legs can appear several times. """ fareProducts: [FareProductUse] + + """ + The date and time when this leg begins. Format: Unix timestamp in milliseconds. + """ + startTime: Long @deprecated(reason: "Use `start` instead which contains timezone information.") + + """ + The date and time when this leg ends. Format: Unix timestamp in milliseconds. + """ + endTime: Long @deprecated(reason: "Use `end` instead which contains timezone information.") + } """A span of time.""" @@ -2267,15 +2268,11 @@ type Place { """Longitude of the place (WGS 84)""" lon: Float! - """ - The time the rider will arrive at the place. Format: Unix timestamp in milliseconds. - """ - arrivalTime: Long! + "The time the rider will arrive at the place." + arrival: DateTime - """ - The time the rider will depart the place. Format: Unix timestamp in milliseconds. - """ - departureTime: Long! + "The time the rider will depart the place." + departure: DateTime """The stop related to the place.""" stop: Stop @@ -2313,6 +2310,16 @@ type Place { """The car parking related to the place""" carPark: CarPark @deprecated(reason: "carPark is deprecated. Use vehicleParking instead.") + + """ + The time the rider will arrive at the place. Format: Unix timestamp in milliseconds. + """ + arrivalTime: Long! @deprecated(reason: "Use `arrival` which includes timezone information.") + + """ + The time the rider will depart the place. Format: Unix timestamp in milliseconds. + """ + departureTime: Long! @deprecated(reason: "Use `departure` which includes timezone information.") } type placeAtDistance implements Node { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 408b1c17ed5..1a4d09f5756 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -14,15 +14,15 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departureTime" : 1580641200000, - "arrivalTime" : 1580641200000 + "departure" : "2020-02-02T11:00:00Z", + "arrival" : "2020-02-02T11:00:00Z" }, "to" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departureTime" : 1580641220000, - "arrivalTime" : 1580641220000 + "departure" : "2020-02-02T11:00:20Z", + "arrival" : "2020-02-02T11:00:20Z" }, "route" : null, "legGeometry" : null @@ -35,15 +35,15 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departureTime" : 1580641260000, - "arrivalTime" : 1580641260000 + "departure" : "2020-02-02T11:01:00Z", + "arrival" : "2020-02-02T11:01:00Z" }, "to" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departureTime" : 1580642100000, - "arrivalTime" : 1580642100000 + "departure" : "2020-02-02T11:15:00Z", + "arrival" : "2020-02-02T11:15:00Z" }, "route" : { "gtfsId" : "F:BUS", @@ -62,15 +62,15 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departureTime" : 1580643000000, - "arrivalTime" : 1580643000000 + "departure" : "2020-02-02T11:30:00Z", + "arrival" : "2020-02-02T11:30:00Z" }, "to" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departureTime" : 1580644200000, - "arrivalTime" : 1580644200000 + "departure" : "2020-02-02T11:50:00Z", + "arrival" : "2020-02-02T11:50:00Z" }, "route" : { "gtfsId" : "F:2", @@ -89,15 +89,15 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departureTime" : 1580644200000, - "arrivalTime" : 1580644200000 + "departure" : "2020-02-02T11:50:00Z", + "arrival" : "2020-02-02T11:50:00Z" }, "to" : { "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departureTime" : 1580644800000, - "arrivalTime" : 1580644800000 + "departure" : "2020-02-02T12:00:00Z", + "arrival" : "2020-02-02T12:00:00Z" }, "route" : null, "legGeometry" : null diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 4e638d93759..c37499eb5e7 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -27,15 +27,15 @@ name lat lon - departureTime - arrivalTime + departure + arrival } to { name lat lon - departureTime - arrivalTime + departure + arrival } route { gtfsId From cb938be6c488c06666bf69c36e4fb326fe6f9830 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 14:35:52 +0200 Subject: [PATCH 06/83] Introduce consolidated times for legs --- docs/apis/GraphQL-Tutorial.md | 12 ++++- .../impl/CombinedInterlinedTransitLeg.java | 11 +++++ .../ext/flex/FlexibleTransitLeg.java | 11 +++++ .../apis/gtfs/datafetchers/LegImpl.java | 10 ++-- .../gtfs/generated/GraphQLDataFetchers.java | 13 ++++- .../apis/gtfs/generated/graphql-codegen.yml | 1 + .../org/opentripplanner/model/plan/Leg.java | 3 ++ .../opentripplanner/model/plan/LegTime.java | 17 +++++++ .../model/plan/ScheduledTransitLeg.java | 10 ++++ .../opentripplanner/model/plan/StreetLeg.java | 10 ++++ .../model/plan/UnknownTransitPathLeg.java | 10 ++++ .../opentripplanner/apis/gtfs/schema.graphqls | 11 ++++- .../apis/gtfs/expectations/plan-extended.json | 48 +++++++++++++++---- .../apis/gtfs/expectations/plan.json | 48 +++++++++++++++---- .../apis/gtfs/queries/plan-extended.graphql | 12 ++++- .../apis/gtfs/queries/plan.graphql | 12 ++++- 16 files changed, 208 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/opentripplanner/model/plan/LegTime.java diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 480e2ef10ee..c98411fd20d 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -92,8 +92,16 @@ Most people want to get routing results out of OTP, so lets see the query for th end legs { mode - start - end + start { + scheduled + actual + delay + } + end { + scheduled + actual + delay + } from { name lat diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 0e9c10de7eb..43266f8e35f 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -9,6 +9,7 @@ import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Leg; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; @@ -56,6 +57,16 @@ public Trip getTrip() { return first.getTrip(); } + @Override + public LegTime start() { + return LegTime.of(getEndTime(), getDepartureDelay()); + } + + @Override + public LegTime end() { + return LegTime.of(getStartTime(), getArrivalDelay()); + } + @Override public ZonedDateTime getStartTime() { return first.getStartTime(); diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index 0e83372175a..e0bdb6cc899 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,6 +16,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -84,6 +85,16 @@ public Accessibility getTripWheelchairAccessibility() { return edge.getFlexTrip().getTrip().getWheelchairBoarding(); } + @Override + public LegTime start() { + return LegTime.of(startTime, getArrivalDelay()); + } + + @Override + public LegTime end() { + return LegTime.of(endTime, getDepartureDelay()); + } + @Override @Nonnull public TransitMode getMode() { diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 50e935ce7ea..093f6bda5e1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -2,7 +2,6 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.time.OffsetDateTime; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -19,6 +18,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,8 +79,8 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { - return environment -> getSource(environment).getEndTime().toOffsetDateTime(); + public DataFetcher end() { + return environment -> getSource(environment).end(); } @Override @@ -223,8 +223,8 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { - return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + public DataFetcher start() { + return environment -> getSource(environment).start(); } @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 431cf874152..c1d9df3678d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,6 +36,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -442,7 +443,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -484,7 +485,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -499,6 +500,14 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } + public interface GraphQLLegTime { + public DataFetcher actual(); + + public DataFetcher delay(); + + public DataFetcher scheduled(); + } + /** A span of time. */ public interface GraphQLLocalTimeSpan { public DataFetcher from(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 24cde3afe43..f1d984a9ecd 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -60,6 +60,7 @@ config: InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField Itinerary: org.opentripplanner.model.plan.Itinerary#Itinerary Leg: org.opentripplanner.model.plan.Leg#Leg + LegTime: org.opentripplanner.model.plan.LegTime#LegTime Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 05213dbdf5e..1e6ca916a63 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,6 +200,9 @@ default Accessibility getTripWheelchairAccessibility() { return null; } + LegTime start(); + LegTime end(); + /** * The date and time this leg begins. */ diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java new file mode 100644 index 00000000000..a65a3109987 --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -0,0 +1,17 @@ +package org.opentripplanner.model.plan; + +import java.time.Duration; +import java.time.ZonedDateTime; +import javax.annotation.Nonnull; + +public record LegTime(ZonedDateTime scheduled, ZonedDateTime actual, Duration delay) { + @Nonnull + public static LegTime of(ZonedDateTime realtime, int delaySecs) { + var delay = Duration.ofSeconds(delaySecs); + return new LegTime(realtime.minus(delay), realtime, delay); + } + @Nonnull + public static LegTime ofStatic(ZonedDateTime staticTime) { + return new LegTime(staticTime, staticTime, Duration.ZERO); + } +} diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 876567035dd..0e4923f9de1 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -162,6 +162,16 @@ public Accessibility getTripWheelchairAccessibility() { return tripTimes.getWheelchairAccessibility(); } + @Override + public LegTime start() { + return LegTime.of(startTime, getDepartureDelay()); + } + + @Override + public LegTime end() { + return LegTime.of(endTime, getArrivalDelay()); + } + @Override @Nonnull public TransitMode getMode() { diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 319c9e01f69..6384159a4ec 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -156,6 +156,16 @@ public boolean hasSameMode(Leg other) { return other instanceof StreetLeg oSL && mode.equals(oSL.mode); } + @Override + public LegTime start() { + return LegTime.ofStatic(startTime); + } + + @Override + public LegTime end() { + return LegTime.ofStatic(endTime); + } + @Override public Leg withTimeShift(Duration duration) { return StreetLegBuilder diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index 382a09d34e2..df43bbcb411 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -68,6 +68,16 @@ public boolean hasSameMode(Leg other) { return false; } + @Override + public LegTime start() { + return LegTime.ofStatic(startTime); + } + + @Override + public LegTime end() { + return LegTime.ofStatic(endTime); + } + @Override public double getDistanceMeters() { return UNKNOWN; diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index f6abf30aacb..0f4bba3de18 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1645,9 +1645,16 @@ type RideHailingEstimate { scalar DateTime +type LegTime { + scheduled: DateTime + actual: DateTime + delay: Duration +} + type Leg { - start: DateTime - end: DateTime + + start: LegTime + end: LegTime """ For transit leg, the offset from the scheduled departure time of the boarding diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 739e0453e08..5ccd1e7bdea 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -18,8 +18,16 @@ "legs" : [ { "mode" : "WALK", - "start" : "2020-02-02T11:00:00Z", - "end" : "2020-02-02T11:00:20Z", + "start" : { + "scheduled" : "2020-02-02T11:00:00Z", + "actual" : "2020-02-02T11:00:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:00:20Z", + "actual" : "2020-02-02T11:00:20Z", + "delay" : "PT0S" + }, "from" : { "name" : "A", "lat" : 5.0, @@ -45,8 +53,16 @@ }, { "mode" : "BUS", - "start" : "2020-02-02T11:01:00Z", - "end" : "2020-02-02T11:15:00Z", + "start" : { + "scheduled" : "2020-02-02T11:01:00Z", + "actual" : "2020-02-02T11:01:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:15:00Z", + "actual" : "2020-02-02T11:15:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "B", "lat" : 6.0, @@ -74,8 +90,16 @@ }, { "mode" : "RAIL", - "start" : "2020-02-02T11:30:00Z", - "end" : "2020-02-02T11:50:00Z", + "start" : { + "scheduled" : "2020-02-02T11:30:00Z", + "actual" : "2020-02-02T11:30:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "C", "lat" : 7.0, @@ -123,8 +147,16 @@ }, { "mode" : "CAR", - "start" : "2020-02-02T11:50:00Z", - "end" : "2020-02-02T12:00:00Z", + "start" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T12:00:00Z", + "actual" : "2020-02-02T12:00:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 1a4d09f5756..6865eb282d4 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -8,8 +8,16 @@ "legs" : [ { "mode" : "WALK", - "start" : "2020-02-02T11:00:00Z", - "end" : "2020-02-02T11:00:20Z", + "start" : { + "scheduled" : "2020-02-02T11:00:00Z", + "actual" : "2020-02-02T11:00:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:00:20Z", + "actual" : "2020-02-02T11:00:20Z", + "delay" : "PT0S" + }, "from" : { "name" : "A", "lat" : 5.0, @@ -29,8 +37,16 @@ }, { "mode" : "BUS", - "start" : "2020-02-02T11:01:00Z", - "end" : "2020-02-02T11:15:00Z", + "start" : { + "scheduled" : "2020-02-02T11:01:00Z", + "actual" : "2020-02-02T11:01:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:15:00Z", + "actual" : "2020-02-02T11:15:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "B", "lat" : 6.0, @@ -56,8 +72,16 @@ }, { "mode" : "RAIL", - "start" : "2020-02-02T11:30:00Z", - "end" : "2020-02-02T11:50:00Z", + "start" : { + "scheduled" : "2020-02-02T11:30:00Z", + "actual" : "2020-02-02T11:30:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "C", "lat" : 7.0, @@ -83,8 +107,16 @@ }, { "mode" : "CAR", - "start" : "2020-02-02T11:50:00Z", - "end" : "2020-02-02T12:00:00Z", + "start" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T12:00:00Z", + "actual" : "2020-02-02T12:00:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index cde918e43b0..3d4ec134b47 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -31,8 +31,16 @@ walkTime legs { mode - start - end + start { + scheduled + actual + delay + } + end { + scheduled + actual + delay + } from { name lat diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index c37499eb5e7..5af473c7323 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -21,8 +21,16 @@ end legs { mode - start - end + start { + scheduled + actual + delay + } + end { + scheduled + actual + delay + } from { name lat From 6e620e77b671873e5abf8adad121f951dccc9214 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 14:54:37 +0200 Subject: [PATCH 07/83] Update deprecation notice --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 0f4bba3de18..8fdfd0133d8 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1834,12 +1834,12 @@ type Leg { """ The date and time when this leg begins. Format: Unix timestamp in milliseconds. """ - startTime: Long @deprecated(reason: "Use `start` instead which contains timezone information.") + startTime: Long @deprecated(reason: "Use `start.actual` instead which contains timezone information.") """ The date and time when this leg ends. Format: Unix timestamp in milliseconds. """ - endTime: Long @deprecated(reason: "Use `end` instead which contains timezone information.") + endTime: Long @deprecated(reason: "Use `end.actual` instead which contains timezone information.") } From d1a123acdb0b99408c86322e897502681a6e0a63 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 15:38:36 +0200 Subject: [PATCH 08/83] Add ISO times to stop time --- .../apis/gtfs/datafetchers/StoptimeImpl.java | 23 ++++++++++++ .../gtfs/generated/GraphQLDataFetchers.java | 4 ++ .../opentripplanner/model/TripTimeOnDate.java | 37 +++++++++++++++++++ .../opentripplanner/model/plan/LegTime.java | 3 +- .../opentripplanner/apis/gtfs/schema.graphqls | 4 ++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java index faf59ef9d6e..e7881aea867 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -2,20 +2,39 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.ZoneId; +import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.StopTime; import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; public class StoptimeImpl implements GraphQLDataFetchers.GraphQLStoptime { + @Override + public DataFetcher arrival() { + return environment -> { + var tripTime = getSource(environment); + return tripTime.arrival(getZoneId(environment)); + }; + } + @Override public DataFetcher arrivalDelay() { return environment -> missingValueToNull(getSource(environment).getArrivalDelay()); } + @Override + public DataFetcher departure() { + return environment -> { + var tripTime = getSource(environment); + return tripTime.departure(getZoneId(environment)); + }; + } + @Override public DataFetcher departureDelay() { return environment -> getSource(environment).getDepartureDelay(); @@ -113,6 +132,10 @@ private TripTimeOnDate getSource(DataFetchingEnvironment environment) { return environment.getSource(); } + private ZoneId getZoneId(DataFetchingEnvironment environment) { + return environment.getContext().transitService().getTimeZone(); + } + /** * Generally the missing values are removed during the graph build. However, for flex trips they * are not and have to be converted to null here. diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index c1d9df3678d..832d3c65d31 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -980,8 +980,12 @@ public interface GraphQLStopRelationship { /** Stoptime represents the time when a specific trip arrives to or departs from a specific stop. */ public interface GraphQLStoptime { + public DataFetcher arrival(); + public DataFetcher arrivalDelay(); + public DataFetcher departure(); + public DataFetcher departureDelay(); public DataFetcher dropoffType(); diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 9ba85d6b532..24f33cf35b6 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -1,11 +1,16 @@ package org.opentripplanner.model; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import javax.annotation.Nonnull; import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.OccupancyStatus; @@ -268,4 +273,36 @@ public BookingInfo getPickupBookingInfo() { public BookingInfo getDropOffBookingInfo() { return tripTimes.getDropOffBookingInfo(stopIndex); } + + public LegTime arrival(ZoneId zoneId) { + var delay = getArrivalDelay(); + var scheduled = getScheduledArrival(); + var actual = getActualDeparture(); + return buildLegTime(zoneId, scheduled, actual, delay); + } + + public LegTime departure(ZoneId zoneId) { + var delay = getDepartureDelay(); + var scheduled = getScheduledDeparture(); + var actual = getActualDeparture(); + return buildLegTime(zoneId, scheduled, actual, delay); + } + + @Nonnull + private LegTime buildLegTime( + ZoneId zoneId, + int scheduled, + int actual, + int delay + ) { + var midnight = serviceDate.atStartOfDay(zoneId); + var scheduledTime = midnight.plusSeconds(scheduled); + ZonedDateTime actualTime; + if (actual == UNDEFINED) { + actualTime = null; + } else { + actualTime = midnight.plusSeconds(actual); + } + return new LegTime(scheduledTime, actualTime, Duration.ofSeconds(delay)); + } } diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index a65a3109987..5a940a40b2c 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -3,8 +3,9 @@ import java.time.Duration; import java.time.ZonedDateTime; import javax.annotation.Nonnull; +import javax.annotation.Nullable; -public record LegTime(ZonedDateTime scheduled, ZonedDateTime actual, Duration delay) { +public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable ZonedDateTime actual, Duration delay) { @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 8fdfd0133d8..9e04f493c1a 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -3896,6 +3896,10 @@ type Stoptime { """ stopPosition: Int + + departure: LegTime + arrival: LegTime + """ Scheduled arrival time. Format: seconds since midnight of the departure date """ From d5f4926545eaf8d533a059fdb16410ec0efa07f5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 Nov 2023 18:24:10 +0100 Subject: [PATCH 09/83] Rename LegTime to LegTimes --- .../impl/CombinedInterlinedTransitLeg.java | 10 ++++----- .../ext/flex/FlexibleTransitLeg.java | 10 ++++----- .../apis/gtfs/datafetchers/LegImpl.java | 6 ++--- .../apis/gtfs/datafetchers/StoptimeImpl.java | 6 ++--- .../gtfs/generated/GraphQLDataFetchers.java | 11 +++++----- .../opentripplanner/model/TripTimeOnDate.java | 15 +++++-------- .../org/opentripplanner/model/plan/Leg.java | 4 ++-- .../opentripplanner/model/plan/LegTime.java | 18 --------------- .../opentripplanner/model/plan/LegTimes.java | 22 +++++++++++++++++++ .../model/plan/ScheduledTransitLeg.java | 8 +++---- .../opentripplanner/model/plan/StreetLeg.java | 8 +++---- .../model/plan/UnknownTransitPathLeg.java | 8 +++---- 12 files changed, 62 insertions(+), 64 deletions(-) delete mode 100644 src/main/java/org/opentripplanner/model/plan/LegTime.java create mode 100644 src/main/java/org/opentripplanner/model/plan/LegTimes.java diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 43266f8e35f..c1497373851 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -9,8 +9,8 @@ import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; -import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Leg; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -58,13 +58,13 @@ public Trip getTrip() { } @Override - public LegTime start() { - return LegTime.of(getEndTime(), getDepartureDelay()); + public LegTimes start() { + return LegTimes.of(getEndTime(), getDepartureDelay()); } @Override - public LegTime end() { - return LegTime.of(getStartTime(), getArrivalDelay()); + public LegTimes end() { + return LegTimes.of(getStartTime(), getArrivalDelay()); } @Override diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index e0bdb6cc899..25caa9089e9 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,7 +16,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -86,13 +86,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTime start() { - return LegTime.of(startTime, getArrivalDelay()); + public LegTimes start() { + return LegTimes.of(startTime, getArrivalDelay()); } @Override - public LegTime end() { - return LegTime.of(endTime, getDepartureDelay()); + public LegTimes end() { + return LegTimes.of(endTime, getDepartureDelay()); } @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 093f6bda5e1..239ba0e28cf 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -18,7 +18,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,7 +79,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -223,7 +223,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java index e7881aea867..85ef1608771 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -8,14 +8,14 @@ import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.StopTime; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; public class StoptimeImpl implements GraphQLDataFetchers.GraphQLStoptime { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> { var tripTime = getSource(environment); return tripTime.arrival(getZoneId(environment)); @@ -28,7 +28,7 @@ public DataFetcher arrivalDelay() { } @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> { var tripTime = getSource(environment); return tripTime.departure(getZoneId(environment)); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 832d3c65d31..9ab6f39bb77 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,7 +36,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -51,7 +51,6 @@ import org.opentripplanner.service.realtimevehicles.model.RealtimeVehicle.StopRelationship; import org.opentripplanner.service.vehiclerental.model.RentalVehicleEntityCounts; import org.opentripplanner.service.vehiclerental.model.RentalVehicleType; -import org.opentripplanner.service.vehiclerental.model.RentalVehicleTypeCount; import org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStation; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; @@ -443,7 +442,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -485,7 +484,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -980,11 +979,11 @@ public interface GraphQLStopRelationship { /** Stoptime represents the time when a specific trip arrives to or departs from a specific stop. */ public interface GraphQLStoptime { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalDelay(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureDelay(); diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 24f33cf35b6..c1c916eb33f 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -10,7 +10,7 @@ import java.util.List; import javax.annotation.Nonnull; import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.OccupancyStatus; @@ -274,14 +274,14 @@ public BookingInfo getDropOffBookingInfo() { return tripTimes.getDropOffBookingInfo(stopIndex); } - public LegTime arrival(ZoneId zoneId) { + public LegTimes arrival(ZoneId zoneId) { var delay = getArrivalDelay(); var scheduled = getScheduledArrival(); var actual = getActualDeparture(); return buildLegTime(zoneId, scheduled, actual, delay); } - public LegTime departure(ZoneId zoneId) { + public LegTimes departure(ZoneId zoneId) { var delay = getDepartureDelay(); var scheduled = getScheduledDeparture(); var actual = getActualDeparture(); @@ -289,12 +289,7 @@ public LegTime departure(ZoneId zoneId) { } @Nonnull - private LegTime buildLegTime( - ZoneId zoneId, - int scheduled, - int actual, - int delay - ) { + private LegTimes buildLegTime(ZoneId zoneId, int scheduled, int actual, int delay) { var midnight = serviceDate.atStartOfDay(zoneId); var scheduledTime = midnight.plusSeconds(scheduled); ZonedDateTime actualTime; @@ -303,6 +298,6 @@ private LegTime buildLegTime( } else { actualTime = midnight.plusSeconds(actual); } - return new LegTime(scheduledTime, actualTime, Duration.ofSeconds(delay)); + return new LegTimes(scheduledTime, actualTime, Duration.ofSeconds(delay)); } } diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 1e6ca916a63..906e09989c5 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,8 +200,8 @@ default Accessibility getTripWheelchairAccessibility() { return null; } - LegTime start(); - LegTime end(); + LegTimes start(); + LegTimes end(); /** * The date and time this leg begins. diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java deleted file mode 100644 index 5a940a40b2c..00000000000 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.opentripplanner.model.plan; - -import java.time.Duration; -import java.time.ZonedDateTime; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable ZonedDateTime actual, Duration delay) { - @Nonnull - public static LegTime of(ZonedDateTime realtime, int delaySecs) { - var delay = Duration.ofSeconds(delaySecs); - return new LegTime(realtime.minus(delay), realtime, delay); - } - @Nonnull - public static LegTime ofStatic(ZonedDateTime staticTime) { - return new LegTime(staticTime, staticTime, Duration.ZERO); - } -} diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java new file mode 100644 index 00000000000..e6614b2ed01 --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -0,0 +1,22 @@ +package org.opentripplanner.model.plan; + +import java.time.Duration; +import java.time.ZonedDateTime; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public record LegTimes( + @Nonnull ZonedDateTime scheduled, + @Nullable ZonedDateTime actual, + @Nullable Duration delay +) { + @Nonnull + public static LegTimes of(ZonedDateTime realtime, int delaySecs) { + var delay = Duration.ofSeconds(delaySecs); + return new LegTimes(realtime.minus(delay), realtime, delay); + } + @Nonnull + public static LegTimes ofStatic(ZonedDateTime staticTime) { + return new LegTimes(staticTime, staticTime, Duration.ZERO); + } +} diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 0e4923f9de1..4f6bf98def3 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -163,13 +163,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTime start() { - return LegTime.of(startTime, getDepartureDelay()); + public LegTimes start() { + return LegTimes.of(startTime, getDepartureDelay()); } @Override - public LegTime end() { - return LegTime.of(endTime, getArrivalDelay()); + public LegTimes end() { + return LegTimes.of(endTime, getArrivalDelay()); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 6384159a4ec..41062995cf4 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTime start() { - return LegTime.ofStatic(startTime); + public LegTimes start() { + return LegTimes.ofStatic(startTime); } @Override - public LegTime end() { - return LegTime.ofStatic(endTime); + public LegTimes end() { + return LegTimes.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index df43bbcb411..4dfefb086e3 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -69,13 +69,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTime start() { - return LegTime.ofStatic(startTime); + public LegTimes start() { + return LegTimes.ofStatic(startTime); } @Override - public LegTime end() { - return LegTime.ofStatic(endTime); + public LegTimes end() { + return LegTimes.ofStatic(endTime); } @Override From 2b21e8f11bd269787a9de3c22aa61df5ab9d6c35 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 Nov 2023 18:31:33 +0100 Subject: [PATCH 10/83] Move deprecated methods to bottom --- .../opentripplanner/apis/gtfs/schema.graphqls | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 9e04f493c1a..2d454d6a3e8 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1645,7 +1645,7 @@ type RideHailingEstimate { scalar DateTime -type LegTime { +type LegTimes { scheduled: DateTime actual: DateTime delay: Duration @@ -1653,22 +1653,8 @@ type LegTime { type Leg { - start: LegTime - end: LegTime - - """ - For transit leg, the offset from the scheduled departure time of the boarding - stop in this leg, i.e. scheduled time of departure at boarding stop = - `startTime - departureDelay` - """ - departureDelay: Int - - """ - For transit leg, the offset from the scheduled arrival time of the alighting - stop in this leg, i.e. scheduled time of arrival at alighting stop = `endTime - - arrivalDelay` - """ - arrivalDelay: Int + start: LegTimes + end: LegTimes """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode @@ -1841,6 +1827,20 @@ type Leg { """ endTime: Long @deprecated(reason: "Use `end.actual` instead which contains timezone information.") + """ + For transit leg, the offset from the scheduled departure time of the boarding + stop in this leg, i.e. scheduled time of departure at boarding stop = + `startTime - departureDelay` + """ + departureDelay: Int @deprecated(reason: "Use `end.delay` instead.") + + """ + For transit leg, the offset from the scheduled arrival time of the alighting + stop in this leg, i.e. scheduled time of arrival at alighting stop = `endTime + - arrivalDelay` + """ + arrivalDelay: Int @deprecated(reason: "Use `start.delay` instead.") + } """A span of time.""" From e12ecfbb1f80811a374cda06912f2aa2bf2eb61d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 7 Nov 2023 09:21:51 +0100 Subject: [PATCH 11/83] Rename LegTime to LegTimes --- .../apis/gtfs/generated/GraphQLDataFetchers.java | 3 ++- .../opentripplanner/apis/gtfs/generated/graphql-codegen.yml | 2 +- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 9ab6f39bb77..f95496990a2 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -51,6 +51,7 @@ import org.opentripplanner.service.realtimevehicles.model.RealtimeVehicle.StopRelationship; import org.opentripplanner.service.vehiclerental.model.RentalVehicleEntityCounts; import org.opentripplanner.service.vehiclerental.model.RentalVehicleType; +import org.opentripplanner.service.vehiclerental.model.RentalVehicleTypeCount; import org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStation; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; @@ -499,7 +500,7 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } - public interface GraphQLLegTime { + public interface GraphQLLegTimes { public DataFetcher actual(); public DataFetcher delay(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index f1d984a9ecd..c248d787088 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -60,7 +60,7 @@ config: InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField Itinerary: org.opentripplanner.model.plan.Itinerary#Itinerary Leg: org.opentripplanner.model.plan.Leg#Leg - LegTime: org.opentripplanner.model.plan.LegTime#LegTime + LegTimes: org.opentripplanner.model.plan.LegTimes#LegTimes Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2d454d6a3e8..82c0fb9c207 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -3897,8 +3897,8 @@ type Stoptime { stopPosition: Int - departure: LegTime - arrival: LegTime + departure: LegTimes + arrival: LegTimes """ Scheduled arrival time. Format: seconds since midnight of the departure date From 644dbcb86d9d85a1c53da3f7323bd873707aebeb Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 7 Nov 2023 09:40:29 +0100 Subject: [PATCH 12/83] Remove changes to StopTime --- .../apis/gtfs/datafetchers/StoptimeImpl.java | 23 ------------- .../gtfs/generated/GraphQLDataFetchers.java | 4 --- .../opentripplanner/model/TripTimeOnDate.java | 32 ------------------- .../opentripplanner/apis/gtfs/schema.graphqls | 4 --- 4 files changed, 63 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java index 85ef1608771..faf59ef9d6e 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -2,39 +2,20 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.time.ZoneId; -import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.StopTime; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; public class StoptimeImpl implements GraphQLDataFetchers.GraphQLStoptime { - @Override - public DataFetcher arrival() { - return environment -> { - var tripTime = getSource(environment); - return tripTime.arrival(getZoneId(environment)); - }; - } - @Override public DataFetcher arrivalDelay() { return environment -> missingValueToNull(getSource(environment).getArrivalDelay()); } - @Override - public DataFetcher departure() { - return environment -> { - var tripTime = getSource(environment); - return tripTime.departure(getZoneId(environment)); - }; - } - @Override public DataFetcher departureDelay() { return environment -> getSource(environment).getDepartureDelay(); @@ -132,10 +113,6 @@ private TripTimeOnDate getSource(DataFetchingEnvironment environment) { return environment.getSource(); } - private ZoneId getZoneId(DataFetchingEnvironment environment) { - return environment.getContext().transitService().getTimeZone(); - } - /** * Generally the missing values are removed during the graph build. However, for flex trips they * are not and have to be converted to null here. diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index f95496990a2..d9991d9dff3 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -980,12 +980,8 @@ public interface GraphQLStopRelationship { /** Stoptime represents the time when a specific trip arrives to or departs from a specific stop. */ public interface GraphQLStoptime { - public DataFetcher arrival(); - public DataFetcher arrivalDelay(); - public DataFetcher departure(); - public DataFetcher departureDelay(); public DataFetcher dropoffType(); diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index c1c916eb33f..9ba85d6b532 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -1,16 +1,11 @@ package org.opentripplanner.model; -import java.time.Duration; import java.time.Instant; import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import javax.annotation.Nonnull; import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.OccupancyStatus; @@ -273,31 +268,4 @@ public BookingInfo getPickupBookingInfo() { public BookingInfo getDropOffBookingInfo() { return tripTimes.getDropOffBookingInfo(stopIndex); } - - public LegTimes arrival(ZoneId zoneId) { - var delay = getArrivalDelay(); - var scheduled = getScheduledArrival(); - var actual = getActualDeparture(); - return buildLegTime(zoneId, scheduled, actual, delay); - } - - public LegTimes departure(ZoneId zoneId) { - var delay = getDepartureDelay(); - var scheduled = getScheduledDeparture(); - var actual = getActualDeparture(); - return buildLegTime(zoneId, scheduled, actual, delay); - } - - @Nonnull - private LegTimes buildLegTime(ZoneId zoneId, int scheduled, int actual, int delay) { - var midnight = serviceDate.atStartOfDay(zoneId); - var scheduledTime = midnight.plusSeconds(scheduled); - ZonedDateTime actualTime; - if (actual == UNDEFINED) { - actualTime = null; - } else { - actualTime = midnight.plusSeconds(actual); - } - return new LegTimes(scheduledTime, actualTime, Duration.ofSeconds(delay)); - } } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 82c0fb9c207..490228ad01c 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -3896,10 +3896,6 @@ type Stoptime { """ stopPosition: Int - - departure: LegTimes - arrival: LegTimes - """ Scheduled arrival time. Format: seconds since midnight of the departure date """ From f69ca284e3f37b4922e629dc348f5008785280f4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 7 Nov 2023 10:03:29 +0100 Subject: [PATCH 13/83] Rename to OffsetDateTime --- .../opentripplanner/apis/gtfs/GraphQLScalars.java | 4 ++-- .../apis/gtfs/GtfsGraphQLIndex.java | 2 +- .../org/opentripplanner/apis/gtfs/schema.graphqls | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 0e21df48dc1..3e376b60b35 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -54,9 +54,9 @@ public String parseLiteral(Object input) { ) .build(); - public static GraphQLScalarType dateTimeScalar = GraphQLScalarType + public static GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType .newScalar() - .name("DateTime") + .name("OffsetDateTime") .coercing( new Coercing() { @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 5ddfb2ba6d1..0d76de16dc1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -111,7 +111,7 @@ protected static GraphQLSchema buildSchema() { .scalar(GraphQLScalars.geoJsonScalar) .scalar(GraphQLScalars.graphQLIDScalar) .scalar(GraphQLScalars.gramsScalar) - .scalar(GraphQLScalars.dateTimeScalar) + .scalar(GraphQLScalars.offsetDateTimeScalar) .scalar(ExtendedScalars.GraphQLLong) .type("Node", type -> type.typeResolver(new NodeTypeResolver())) .type("PlaceInterface", type -> type.typeResolver(new PlaceInterfaceTypeResolver())) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 490228ad01c..0ca9d2e8011 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1507,8 +1507,8 @@ type Itinerary { """ endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") - start: DateTime - end: DateTime + start: OffsetDateTime + end: OffsetDateTime """Duration of the trip on this itinerary, in seconds.""" duration: Long @@ -1643,11 +1643,11 @@ type RideHailingEstimate { productName: String } -scalar DateTime +scalar OffsetDateTime type LegTimes { - scheduled: DateTime - actual: DateTime + scheduled: OffsetDateTime + actual: OffsetDateTime delay: Duration } @@ -2276,10 +2276,10 @@ type Place { lon: Float! "The time the rider will arrive at the place." - arrival: DateTime + arrival: OffsetDateTime "The time the rider will depart the place." - departure: DateTime + departure: OffsetDateTime """The stop related to the place.""" stop: Stop From f2e394fbc1742469aba55ca37e383517c7267705 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 6 Jan 2024 14:35:46 +0100 Subject: [PATCH 14/83] Regenerate types, move deprecated fields to the bottom --- .../gtfs/generated/GraphQLDataFetchers.java | 6 ++++-- .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../opentripplanner/apis/gtfs/schema.graphqls | 20 +++++++++---------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index d9991d9dff3..639ba7c8744 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -399,6 +399,8 @@ public interface GraphQLItinerary { public DataFetcher elevationLost(); + public DataFetcher emissionsPerPerson(); + public DataFetcher end(); public DataFetcher endTime(); @@ -409,10 +411,10 @@ public interface GraphQLItinerary { public DataFetcher> legs(); - public DataFetcher start(); - public DataFetcher numberOfTransfers(); + public DataFetcher start(); + public DataFetcher startTime(); public DataFetcher> systemNotices(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index c248d787088..ecc7a89fb44 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -26,7 +26,7 @@ config: Polyline: String GeoJson: org.locationtech.jts.geom.Geometry Grams: org.opentripplanner.framework.model.Grams - DateTime: java.time.OffsetDateTime + OffsetDateTime: java.time.OffsetDateTime Duration: java.time.Duration mappers: AbsoluteDirection: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLAbsoluteDirection#GraphQLAbsoluteDirection diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 0ca9d2e8011..15cd4ae8ed3 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1497,16 +1497,6 @@ type DefaultFareProduct implements FareProduct { } type Itinerary { - """ - Time when the user leaves from the origin. Format: Unix timestamp in milliseconds. - """ - startTime: Long @deprecated(reason: "Use `start` instead which includes timezone information.") - - """ - Time when the user arrives to the destination. Format: Unix timestamp in milliseconds. - """ - endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") - start: OffsetDateTime end: OffsetDateTime @@ -1587,6 +1577,16 @@ type Itinerary { and always returns an empty list. Use the leg's `fareProducts` instead. """ fares: [fare] @deprecated(reason: "Use the leg's `fareProducts`.") + + """ + Time when the user leaves from the origin. Format: Unix timestamp in milliseconds. + """ + startTime: Long @deprecated(reason: "Use `start` instead which includes timezone information.") + + """ + Time when the user arrives to the destination. Format: Unix timestamp in milliseconds. + """ + endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") } "A currency" From dc7521e9694bc4810582ad705ee80175e7f12a95 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 6 Jan 2024 14:56:50 +0100 Subject: [PATCH 15/83] Add tests for Duration --- .../opentripplanner/apis/gtfs/schema.graphqls | 7 ++++++ .../apis/gtfs/GraphQLScalarsTest.java | 22 +++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 15cd4ae8ed3..ff60ed183cb 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1621,6 +1621,8 @@ type Money { """" An ISO-8601-formatted duration, i.e. `PT2H30M` for 2 hours and 30 minutes. + +Negative durations are formatted like `PT-10M`. """ scalar Duration @@ -1648,6 +1650,11 @@ scalar OffsetDateTime type LegTimes { scheduled: OffsetDateTime actual: OffsetDateTime + """ + The delay of the vehicle at a certain place. + + If the vehicle is early then this is a negative duration. + """ delay: Duration } diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 90b35a31b9f..1c4472827c5 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -1,22 +1,36 @@ package org.opentripplanner.apis.gtfs; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.of; import com.fasterxml.jackson.core.JsonProcessingException; import graphql.schema.CoercingSerializeException; import java.time.Duration; +import java.util.List; import org.junit.jupiter.api.Assertions; 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.GeometryFactory; import org.opentripplanner.framework.json.ObjectMappers; class GraphQLScalarsTest { - @Test - void duration() { - var string = GraphQLScalars.durationScalar.getCoercing().serialize(Duration.ofMinutes(30)); - assertEquals("PT30M", string); + static List durationCases() { + return List.of( + of(Duration.ofMinutes(30), "PT30M"), + of(Duration.ofHours(23), "PT23H"), + of(Duration.ofMinutes(-10), "PT-10M") + ); + } + + @ParameterizedTest + @MethodSource("durationCases") + void duration(Duration duration, String expected) { + var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); + assertEquals(expected, string); } @Test From d319e5ba67a2e7349bd74197cc61e9dc6047cfa2 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 6 Jan 2024 20:10:46 +0100 Subject: [PATCH 16/83] Add nullability check --- src/main/java/org/opentripplanner/model/plan/LegTimes.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index e6614b2ed01..06b2fb3662b 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -2,6 +2,7 @@ import java.time.Duration; import java.time.ZonedDateTime; +import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -10,6 +11,9 @@ public record LegTimes( @Nullable ZonedDateTime actual, @Nullable Duration delay ) { + public LegTimes { + Objects.requireNonNull(scheduled); + } @Nonnull public static LegTimes of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); From 67895bee4eb0b1d8313e5010848145c834ad49f2 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 17:12:19 +0100 Subject: [PATCH 17/83] Add documentation for OffsetDateTime --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index ff60ed183cb..3b6bdad5fa4 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1645,6 +1645,9 @@ type RideHailingEstimate { productName: String } +""" +An ISO-8601-formatted datetime with offset, i.e. `2023-06-13T14:30+03:00` for 2:30pm on June 13th 2023 at Helsinki's offset from UTC at that time. +""" scalar OffsetDateTime type LegTimes { From 4f757dae87d3f67ec9622df8e49c6894c6445029 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 17:19:29 +0100 Subject: [PATCH 18/83] Add test for intermediate places --- .../apis/gtfs/expectations/plan-extended.json | 20 +++++++++++++++++++ .../apis/gtfs/queries/plan-extended.graphql | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 5ccd1e7bdea..fde24b8697a 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -47,6 +47,7 @@ "generalizedCost" : 40, "headsign" : null, "trip" : null, + "intermediatePlaces" : null, "alerts" : [ ], "rideHailingEstimate" : null, "accessibilityScore" : null @@ -84,6 +85,15 @@ "trip" : { "tripHeadsign" : "Trip headsign 122" }, + "intermediatePlaces" : [ + { + "arrival" : "2020-02-02T11:01:00Z", + "departure" : "2020-02-02T11:01:00Z", + "stop" : { + "name" : "B" + } + } + ], "alerts" : [ ], "rideHailingEstimate" : null, "accessibilityScore" : null @@ -121,6 +131,15 @@ "trip" : { "tripHeadsign" : "Trip headsign 439" }, + "intermediatePlaces" : [ + { + "arrival" : "2020-02-02T11:30:00Z", + "departure" : "2020-02-02T11:30:00Z", + "stop" : { + "name" : "C" + } + } + ], "alerts" : [ { "id" : "QWxlcnQ6Rjphbi1hbGVydA", @@ -176,6 +195,7 @@ "generalizedCost" : 1000, "headsign" : null, "trip" : null, + "intermediatePlaces" : null, "alerts" : [ ], "rideHailingEstimate" : { "provider" : { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index 3d4ec134b47..1c90f773677 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -63,6 +63,13 @@ trip { tripHeadsign } + intermediatePlaces { + arrival + departure + stop { + name + } + } alerts { id alertHeaderText From 980d620e7ba9104720a6b4ef33c0c3ee91ab3f95 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 17:28:20 +0100 Subject: [PATCH 19/83] Add test cases --- .../apis/gtfs/GraphQLScalarsTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 1c4472827c5..079749f3ccc 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -6,6 +6,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import graphql.schema.CoercingSerializeException; import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -14,10 +18,17 @@ import org.junit.jupiter.params.provider.MethodSource; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; +import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.framework.json.ObjectMappers; class GraphQLScalarsTest { + private static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( + LocalDate.of(2024, 2, 4), + LocalTime.MIDNIGHT, + ZoneOffset.UTC + ); + static List durationCases() { return List.of( of(Duration.ofMinutes(30), "PT30M"), @@ -59,4 +70,26 @@ void geoJson() throws JsonProcessingException { .readTree("{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[1,1],[2,2],[0,0]]]}"); assertEquals(jsonNode.toString(), geoJson.toString()); } + + static List offsetDateTimeCases() { + return List.of( + of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), + of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), + "2024-02-04T01:00:00+01:00" + ), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), + "2024-02-03T19:00:00-05:00" + ) + ); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void duration(OffsetDateTime odt, String expected) { + var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + assertEquals(expected, string); + } } From dcaa04a41bd5cd8afd2a34605256d08e5415840c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 18:06:02 +0100 Subject: [PATCH 20/83] Add example for OffsetDateTime --- magidoc.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/magidoc.mjs b/magidoc.mjs index a02976f4bcc..bb138f3c87d 100644 --- a/magidoc.mjs +++ b/magidoc.mjs @@ -35,7 +35,8 @@ To learn how to deactivate it, read the appTitle: 'OTP GTFS GraphQL API', queryGenerationFactories: { 'Polyline': '<>', - 'GeoJson': '<>' + 'GeoJson': '<>', + 'OffsetDateTime': '2024-02-05T18:04:23+0100' }, } }, From 691bdd4735e2bdba6fd5372edd5f68c606dc6cfa Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Feb 2024 14:55:24 +0100 Subject: [PATCH 21/83] Put realtime information into separate object --- .../gtfs/generated/GraphQLDataFetchers.java | 19 +++++++++++---- .../opentripplanner/model/plan/LegTimes.java | 12 ++++------ .../model/plan/ScheduledTransitLeg.java | 12 ++++++++-- .../opentripplanner/apis/gtfs/schema.graphqls | 18 +++++++++----- .../apis/gtfs/expectations/plan-extended.json | 24 +++++++------------ .../apis/gtfs/expectations/plan.json | 24 +++++++------------ .../apis/gtfs/queries/plan-extended.graphql | 12 ++++++---- .../apis/gtfs/queries/plan.graphql | 12 ++++++---- 8 files changed, 74 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 639ba7c8744..fbb246168e1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -503,9 +503,7 @@ public interface GraphQLLeg { } public interface GraphQLLegTimes { - public DataFetcher actual(); - - public DataFetcher delay(); + public DataFetcher realTime(); public DataFetcher scheduled(); } @@ -761,6 +759,12 @@ public interface GraphQLQueryType { public DataFetcher viewer(); } + public interface GraphQLRealtimeInformation { + public DataFetcher predicted(); + + public DataFetcher scheduleOffset(); + } + /** Rental vehicle represents a vehicle that belongs to a rental network. */ public interface GraphQLRentalVehicle { public DataFetcher allowPickupNow(); @@ -1256,6 +1260,10 @@ public interface GraphQLElevationProfileComponent { public DataFetcher elevation(); } + /** + * This type is only here for backwards-compatibility and this API will never return it anymore. + * Please use the leg's `fareProducts` instead. + */ public interface GraphQLFare { public DataFetcher cents(); @@ -1266,7 +1274,10 @@ public interface GraphQLFare { public DataFetcher type(); } - /** Component of the fare (i.e. ticket) for a part of the itinerary */ + /** + * This type is only here for backwards-compatibility and this API will never return it anymore. + * Please use the leg's `fareProducts` instead. + */ public interface GraphQLFareComponent { public DataFetcher cents(); diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index 06b2fb3662b..f3ffe66e0e2 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -1,26 +1,24 @@ package org.opentripplanner.model.plan; import java.time.Duration; +import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimes( - @Nonnull ZonedDateTime scheduled, - @Nullable ZonedDateTime actual, - @Nullable Duration delay -) { +public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable Realtime realTime) { public LegTimes { Objects.requireNonNull(scheduled); } @Nonnull public static LegTimes of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimes(realtime.minus(delay), realtime, delay); + return new LegTimes(realtime.minus(delay), new Realtime(realtime, delay)); } @Nonnull public static LegTimes ofStatic(ZonedDateTime staticTime) { - return new LegTimes(staticTime, staticTime, Duration.ZERO); + return new LegTimes(staticTime, null); } + record Realtime(ZonedDateTime predicted, Duration scheduleOffset) {} } diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 4f6bf98def3..7a1fcacbf31 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -164,12 +164,20 @@ public Accessibility getTripWheelchairAccessibility() { @Override public LegTimes start() { - return LegTimes.of(startTime, getDepartureDelay()); + if (getRealTime()) { + return LegTimes.of(startTime, getDepartureDelay()); + } else { + return LegTimes.ofStatic(startTime); + } } @Override public LegTimes end() { - return LegTimes.of(endTime, getArrivalDelay()); + if (getRealTime()) { + return LegTimes.of(endTime, getArrivalDelay()); + } else { + return LegTimes.ofStatic(endTime); + } } @Override diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 3b6bdad5fa4..3ee9cebe030 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1647,18 +1647,24 @@ type RideHailingEstimate { """ An ISO-8601-formatted datetime with offset, i.e. `2023-06-13T14:30+03:00` for 2:30pm on June 13th 2023 at Helsinki's offset from UTC at that time. + +ISO-8601 allows many different formats but OTP will only return the profile specified in RFC3339. """ -scalar OffsetDateTime +scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") -type LegTimes { - scheduled: OffsetDateTime - actual: OffsetDateTime +type RealtimeInformation { + predicted: OffsetDateTime """ - The delay of the vehicle at a certain place. + The delay or "earliness" of the vehicle at a certain place. If the vehicle is early then this is a negative duration. """ - delay: Duration + scheduleOffset: Duration +} + +type LegTimes { + scheduled: OffsetDateTime + realTime: RealtimeInformation } type Leg { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index fde24b8697a..ade6fa4465d 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -20,13 +20,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "actual" : "2020-02-02T11:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "actual" : "2020-02-02T11:00:20Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "A", @@ -56,13 +54,11 @@ "mode" : "BUS", "start" : { "scheduled" : "2020-02-02T11:01:00Z", - "actual" : "2020-02-02T11:01:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:15:00Z", - "actual" : "2020-02-02T11:15:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "B", @@ -102,13 +98,11 @@ "mode" : "RAIL", "start" : { "scheduled" : "2020-02-02T11:30:00Z", - "actual" : "2020-02-02T11:30:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "C", @@ -168,13 +162,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "actual" : "2020-02-02T12:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "D", diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 6865eb282d4..522f43723df 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -10,13 +10,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "actual" : "2020-02-02T11:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "actual" : "2020-02-02T11:00:20Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "A", @@ -39,13 +37,11 @@ "mode" : "BUS", "start" : { "scheduled" : "2020-02-02T11:01:00Z", - "actual" : "2020-02-02T11:01:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:15:00Z", - "actual" : "2020-02-02T11:15:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "B", @@ -74,13 +70,11 @@ "mode" : "RAIL", "start" : { "scheduled" : "2020-02-02T11:30:00Z", - "actual" : "2020-02-02T11:30:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "C", @@ -109,13 +103,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "actual" : "2020-02-02T12:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "D", diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index 1c90f773677..8b3e0c6db16 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -33,13 +33,17 @@ mode start { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } end { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } from { name diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 5af473c7323..e21a24737ea 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -23,13 +23,17 @@ mode start { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } end { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } from { name From ce002b8da60044966f42ff675507399cf6164578 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Feb 2024 14:58:33 +0100 Subject: [PATCH 22/83] Fix combined leg --- .../ext/fares/impl/CombinedInterlinedTransitLeg.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index c1497373851..0b192a9ec77 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -59,12 +59,12 @@ public Trip getTrip() { @Override public LegTimes start() { - return LegTimes.of(getEndTime(), getDepartureDelay()); + return first.start(); } @Override public LegTimes end() { - return LegTimes.of(getStartTime(), getArrivalDelay()); + return second.end(); } @Override From afb53e193e9f528b8f58430806e329d1ce2845bb Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Feb 2024 15:09:45 +0100 Subject: [PATCH 23/83] Fix tutorial docs --- docs/apis/GraphQL-Tutorial.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index c98411fd20d..0eff55fff7b 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -94,13 +94,17 @@ Most people want to get routing results out of OTP, so lets see the query for th mode start { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } end { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } from { name From 4197aed06d652c52aa2667cb3e9618f91560f260 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 11 Feb 2024 22:24:06 +0100 Subject: [PATCH 24/83] Set transit delay --- .../apis/gtfs/GraphQLIntegrationTest.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index d89afea6f9d..4ce1c181f97 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -52,6 +52,7 @@ import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.RelativeDirection; import org.opentripplanner.model.plan.ScheduledTransitLeg; +import org.opentripplanner.model.plan.ScheduledTransitLegBuilder; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.model.plan.WalkStepBuilder; import org.opentripplanner.routing.alertpatch.AlertCause; @@ -61,7 +62,6 @@ import org.opentripplanner.routing.alertpatch.TimePeriod; import org.opentripplanner.routing.alertpatch.TransitAlert; import org.opentripplanner.routing.api.request.RouteRequest; -import org.opentripplanner.routing.core.FareType; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.GraphFinder; import org.opentripplanner.routing.graphfinder.NearbyStop; @@ -86,6 +86,7 @@ import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; import org.opentripplanner.transit.model.timetable.TripTimesFactory; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.TransitModel; @@ -179,6 +180,23 @@ static void setup() { .carHail(D10m, E) .build(); + i1.transformTransitLegs(tl -> { + if(tl instanceof ScheduledTransitLeg stl){ + var x= new ScheduledTransitLegBuilder<>(stl); + var rtt = (RealTimeTripTimes) stl.getTripTimes(); + + for(var i=0; i < rtt.getNumStops();i++){ + + var time = rtt.getArrivalTime(i); + rtt.updateArrivalTime(i, time + 10*60); + + } + return x.withTripTimes(rtt).build(); + + } + else return tl; + }); + var busLeg = i1.getTransitLeg(1); var railLeg = (ScheduledTransitLeg) i1.getTransitLeg(2); From a534dd34e8dc7b65bce6632e5f46094812e6e470 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 12 Feb 2024 13:16:57 +0100 Subject: [PATCH 25/83] Use 'estimated' instead of 'realTime' --- docs/apis/GraphQL-Tutorial.md | 8 ++-- .../gtfs/generated/GraphQLDataFetchers.java | 8 ++-- .../opentripplanner/model/plan/LegTimes.java | 7 ++- .../opentripplanner/apis/gtfs/schema.graphqls | 6 +-- .../apis/gtfs/GraphQLIntegrationTest.java | 33 +++++++------- .../apis/gtfs/expectations/plan-extended.json | 44 ++++++++++++------- .../apis/gtfs/expectations/plan.json | 36 ++++++++++----- .../apis/gtfs/queries/plan-extended.graphql | 8 ++-- .../apis/gtfs/queries/plan.graphql | 8 ++-- 9 files changed, 90 insertions(+), 68 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 0eff55fff7b..5701ea20954 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -94,15 +94,15 @@ Most people want to get routing results out of OTP, so lets see the query for th mode start { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } end { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index fbb246168e1..b2d37626cf2 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -503,7 +503,7 @@ public interface GraphQLLeg { } public interface GraphQLLegTimes { - public DataFetcher realTime(); + public DataFetcher estimated(); public DataFetcher scheduled(); } @@ -759,10 +759,10 @@ public interface GraphQLQueryType { public DataFetcher viewer(); } - public interface GraphQLRealtimeInformation { - public DataFetcher predicted(); - + public interface GraphQLRealtimeEstimate { public DataFetcher scheduleOffset(); + + public DataFetcher time(); } /** Rental vehicle represents a vehicle that belongs to a rental network. */ diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index f3ffe66e0e2..9206d00b4e3 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -1,24 +1,23 @@ package org.opentripplanner.model.plan; import java.time.Duration; -import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable Realtime realTime) { +public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { public LegTimes { Objects.requireNonNull(scheduled); } @Nonnull public static LegTimes of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimes(realtime.minus(delay), new Realtime(realtime, delay)); + return new LegTimes(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); } @Nonnull public static LegTimes ofStatic(ZonedDateTime staticTime) { return new LegTimes(staticTime, null); } - record Realtime(ZonedDateTime predicted, Duration scheduleOffset) {} + record RealtimeEstimate(ZonedDateTime time, Duration scheduleOffset) {} } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 3ee9cebe030..dc2f61133bf 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1652,8 +1652,8 @@ ISO-8601 allows many different formats but OTP will only return the profile spec """ scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") -type RealtimeInformation { - predicted: OffsetDateTime +type RealtimeEstimate { + time: OffsetDateTime """ The delay or "earliness" of the vehicle at a certain place. @@ -1664,7 +1664,7 @@ type RealtimeInformation { type LegTimes { scheduled: OffsetDateTime - realTime: RealtimeInformation + estimated: RealtimeEstimate } type Leg { diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 4ce1c181f97..f630e0cee3c 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -52,7 +52,6 @@ import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.RelativeDirection; import org.opentripplanner.model.plan.ScheduledTransitLeg; -import org.opentripplanner.model.plan.ScheduledTransitLegBuilder; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.model.plan.WalkStepBuilder; import org.opentripplanner.routing.alertpatch.AlertCause; @@ -116,6 +115,7 @@ class GraphQLIntegrationTest { .parse("2023-02-15T12:03:28+01:00") .toInstant(); static final Instant ALERT_END_TIME = ALERT_START_TIME.plus(1, ChronoUnit.DAYS); + private static final int TEN_MINUTES = 10 * 60; private static GraphQLRequestContext context; @@ -180,22 +180,7 @@ static void setup() { .carHail(D10m, E) .build(); - i1.transformTransitLegs(tl -> { - if(tl instanceof ScheduledTransitLeg stl){ - var x= new ScheduledTransitLegBuilder<>(stl); - var rtt = (RealTimeTripTimes) stl.getTripTimes(); - - for(var i=0; i < rtt.getNumStops();i++){ - - var time = rtt.getArrivalTime(i); - rtt.updateArrivalTime(i, time + 10*60); - - } - return x.withTripTimes(rtt).build(); - - } - else return tl; - }); + add10MinuteDelay(i1); var busLeg = i1.getTransitLeg(1); var railLeg = (ScheduledTransitLeg) i1.getTransitLeg(2); @@ -298,6 +283,20 @@ public TransitAlertService getTransitAlertService() { ); } + private static void add10MinuteDelay(Itinerary i1) { + i1.transformTransitLegs(tl -> { + if (tl instanceof ScheduledTransitLeg stl) { + var rtt = (RealTimeTripTimes) stl.getTripTimes(); + + for (var i = 0; i < rtt.getNumStops(); i++) { + rtt.updateArrivalTime(i, rtt.getArrivalTime(i) + TEN_MINUTES); + rtt.updateDepartureTime(i, rtt.getDepartureTime(i) + TEN_MINUTES); + } + } + return tl; + }); + } + @FilePatternSource(pattern = "src/test/resources/org/opentripplanner/apis/gtfs/queries/*.graphql") @ParameterizedTest(name = "Check GraphQL query in {0}") void graphQL(Path path) throws IOException { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index ade6fa4465d..5a76c7be06e 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -20,11 +20,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "A", @@ -53,12 +53,18 @@ { "mode" : "BUS", "start" : { - "scheduled" : "2020-02-02T11:01:00Z", - "realTime" : null + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:15:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "B", @@ -83,8 +89,8 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:01:00Z", - "departure" : "2020-02-02T11:01:00Z", + "arrival" : "2020-02-02T11:11:00Z", + "departure" : "2020-02-02T11:11:00Z", "stop" : { "name" : "B" } @@ -97,12 +103,18 @@ { "mode" : "RAIL", "start" : { - "scheduled" : "2020-02-02T11:30:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "C", @@ -127,8 +139,8 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:30:00Z", - "departure" : "2020-02-02T11:30:00Z", + "arrival" : "2020-02-02T11:40:00Z", + "departure" : "2020-02-02T11:40:00Z", "stop" : { "name" : "C" } @@ -162,11 +174,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "D", diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 522f43723df..8076a4887d3 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -10,11 +10,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "A", @@ -36,12 +36,18 @@ { "mode" : "BUS", "start" : { - "scheduled" : "2020-02-02T11:01:00Z", - "realTime" : null + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:15:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "B", @@ -69,12 +75,18 @@ { "mode" : "RAIL", "start" : { - "scheduled" : "2020-02-02T11:30:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "C", @@ -103,11 +115,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "D", diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index 8b3e0c6db16..b805a94a3c2 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -33,15 +33,15 @@ mode start { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } end { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index e21a24737ea..4bff431420c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -23,15 +23,15 @@ mode start { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } end { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } From 01b04e0e7b5cb337523ab303cc10d4a822c1a968 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 12 Feb 2024 13:54:40 +0100 Subject: [PATCH 26/83] Use LegTimes for intermediate stops --- docs/apis/GraphQL-Tutorial.md | 24 +++++- .../flex/trip/ScheduledDeviatedTripTest.java | 2 +- .../ext/restapi/mapping/PlaceMapper.java | 10 +-- .../apis/gtfs/datafetchers/LegImpl.java | 10 +-- .../apis/gtfs/datafetchers/PlaceImpl.java | 38 ++++----- .../gtfs/generated/GraphQLDataFetchers.java | 4 +- .../apis/transmodel/model/plan/LegType.java | 2 +- .../model/plan/FrequencyTransitLeg.java | 11 +-- .../org/opentripplanner/model/plan/Leg.java | 2 +- .../opentripplanner/model/plan/LegTimes.java | 9 ++ .../model/plan/ScheduledTransitLeg.java | 23 ++++- .../model/plan/StopArrival.java | 56 ++++--------- .../algorithm/mapping/AlertToLegMapper.java | 6 +- .../opentripplanner/apis/gtfs/schema.graphqls | 4 +- .../apis/gtfs/expectations/plan-extended.json | 32 ++++++- .../apis/gtfs/expectations/plan.json | 84 +++++++++++++++---- .../apis/gtfs/queries/plan-extended.graphql | 16 +++- .../apis/gtfs/queries/plan.graphql | 24 +++++- 18 files changed, 237 insertions(+), 120 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 5701ea20954..863aa8bd57c 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -110,15 +110,31 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - departure - arrival + departure { + scheduled + estimated { + time + scheduleOffset + } + } + arrival { + scheduled + estimated { + time + scheduleOffset + } + } } to { name lat lon - departure - arrival + departure { + scheduled + } + arrival { + scheduled + } } route { gtfsId 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 e0f85676034..c8450a2e7cb 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 @@ -185,7 +185,7 @@ void flexTripInTransitMode() { var intermediateStops = leg.getIntermediateStops(); assertEquals(1, intermediateStops.size()); - assertEquals("zone_1", intermediateStops.get(0).place.stop.getId().getId()); + assertEquals("zone_1", intermediateStops.get(0).place().stop.getId().getId()); EncodedPolyline legGeometry = EncodedPolyline.encode(leg.getLegGeometry()); assertThatPolylinesAreEqual( diff --git a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java index b1eb3410af8..95669d4b7ca 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java @@ -38,11 +38,11 @@ public List mapStopArrivals(Collection domain) { public ApiPlace mapStopArrival(StopArrival domain) { return mapPlace( - domain.place, - domain.arrival, - domain.departure, - domain.stopPosInPattern, - domain.gtfsStopSequence + domain.place(), + domain.arrival().time(), + domain.departure().time(), + domain.stopPosInPattern(), + domain.gtfsStopSequence() ); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 239ba0e28cf..9a6076ecd08 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -100,8 +100,8 @@ public DataFetcher from() { Leg source = getSource(environment); return new StopArrival( source.getFrom(), - source.getStartTime(), - source.getStartTime(), + source.start(), + source.start(), source.getBoardStopPosInPattern(), source.getBoardingGtfsStopSequence() ); @@ -144,7 +144,7 @@ public DataFetcher> intermediateStops() { } return intermediateStops .stream() - .map(intermediateStop -> intermediateStop.place.stop) + .map(intermediateStop -> intermediateStop.place().stop) .filter(Objects::nonNull) .collect(Collectors.toList()); }; @@ -244,8 +244,8 @@ public DataFetcher to() { Leg source = getSource(environment); return new StopArrival( source.getTo(), - source.getEndTime(), - source.getEndTime(), + source.end(), + source.end(), source.getAlightStopPosInPattern(), source.getAlightGtfsStopSequence() ); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 28cd088cf86..8d1434a033c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -2,12 +2,12 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.time.OffsetDateTime; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLVertexType; import org.opentripplanner.apis.gtfs.model.StopPosition; import org.opentripplanner.apis.gtfs.model.StopPosition.PositionAtStop; import org.opentripplanner.framework.graphql.GraphQLUtils; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.VertexType; @@ -19,14 +19,14 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override - public DataFetcher arrival() { - return environment -> getSource(environment).arrival.toOffsetDateTime(); + public DataFetcher arrival() { + return environment -> getSource(environment).arrival(); } @Deprecated @Override public DataFetcher arrivalTime() { - return environment -> getSource(environment).arrival.toInstant().toEpochMilli(); + return environment -> getSource(environment).arrival().time().toInstant().toEpochMilli(); } @Override @@ -37,7 +37,7 @@ public DataFetcher bikePark() { @Override public DataFetcher bikeRentalStation() { return environment -> { - Place place = getSource(environment).place; + Place place = getSource(environment).place(); if (!place.vertexType.equals(VertexType.VEHICLERENTAL)) { return null; @@ -54,35 +54,35 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { - return environment -> getSource(environment).departure.toOffsetDateTime(); + public DataFetcher departure() { + return environment -> getSource(environment).departure(); } @Override public DataFetcher departureTime() { - return environment -> getSource(environment).departure.toInstant().toEpochMilli(); + return environment -> getSource(environment).departure().time().toInstant().toEpochMilli(); } @Override public DataFetcher lat() { - return environment -> getSource(environment).place.coordinate.latitude(); + return environment -> getSource(environment).place().coordinate.latitude(); } @Override public DataFetcher lon() { - return environment -> getSource(environment).place.coordinate.longitude(); + return environment -> getSource(environment).place().coordinate.longitude(); } @Override public DataFetcher name() { return environment -> - GraphQLUtils.getTranslation(getSource(environment).place.name, environment); + GraphQLUtils.getTranslation(getSource(environment).place().name, environment); } @Override public DataFetcher rentalVehicle() { return environment -> { - Place place = getSource(environment).place; + Place place = getSource(environment).place(); if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -97,13 +97,13 @@ public DataFetcher rentalVehicle() { @Override public DataFetcher stop() { - return environment -> getSource(environment).place.stop; + return environment -> getSource(environment).place().stop; } @Override public DataFetcher stopPosition() { return environment -> { - var seq = getSource(environment).gtfsStopSequence; + var seq = getSource(environment).gtfsStopSequence(); if (seq != null) { return new PositionAtStop(seq); } else { @@ -120,7 +120,7 @@ public DataFetcher vehicleParking() { @Override public DataFetcher vehicleRentalStation() { return environment -> { - Place place = getSource(environment).place; + Place place = getSource(environment).place(); if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -136,7 +136,7 @@ public DataFetcher vehicleRentalStation() { @Override public DataFetcher vertexType() { return environment -> { - var place = getSource(environment).place; + var place = getSource(environment).place(); return switch (place.vertexType) { case NORMAL -> GraphQLVertexType.NORMAL.name(); case TRANSIT -> GraphQLVertexType.TRANSIT.name(); @@ -147,7 +147,7 @@ public DataFetcher vertexType() { } private VehicleParking getBikePark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place.vehicleParkingWithEntrance; + var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasBicyclePlaces() @@ -159,7 +159,7 @@ private VehicleParking getBikePark(DataFetchingEnvironment environment) { } private VehicleParking getCarPark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place.vehicleParkingWithEntrance; + var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasAnyCarPlaces() @@ -171,7 +171,7 @@ private VehicleParking getCarPark(DataFetchingEnvironment environment) { } private VehicleParking getVehicleParking(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place.vehicleParkingWithEntrance; + var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; if (vehicleParkingWithEntrance == null) { return null; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index b2d37626cf2..ec8556c45b0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -591,7 +591,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -601,7 +601,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java index be05d00e16d..99ead9fd8c0 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java @@ -340,7 +340,7 @@ public static GraphQLObjectType create( return ( stops .stream() - .map(stop -> stop.place.stop) + .map(stop -> stop.place().stop) .filter(Objects::nonNull) .collect(Collectors.toList()) ); diff --git a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index d2188fb1b0b..31ccbe31a53 100644 --- a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -1,16 +1,9 @@ package org.opentripplanner.model.plan; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nullable; import org.opentripplanner.framework.time.ServiceDateUtils; -import org.opentripplanner.model.transfer.ConstrainedTransfer; -import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; -import org.opentripplanner.transit.model.timetable.TripTimes; /** * One leg of a trip -- that is, a temporally continuous piece of the journey that takes place on a @@ -62,8 +55,8 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime), + LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), + LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 906e09989c5..139d60b5171 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -455,7 +455,7 @@ default Leg withTimeShift(Duration duration) { default Set getFareZones() { var intermediate = getIntermediateStops() .stream() - .flatMap(stopArrival -> stopArrival.place.stop.getFareZones().stream()); + .flatMap(stopArrival -> stopArrival.place().stop.getFareZones().stream()); var start = getFareZones(this.getFrom()); var end = getFareZones(this.getTo()); diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index 9206d00b4e3..5e0802c6e4f 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -19,5 +19,14 @@ public static LegTimes of(ZonedDateTime realtime, int delaySecs) { public static LegTimes ofStatic(ZonedDateTime staticTime) { return new LegTimes(staticTime, null); } + + public ZonedDateTime time() { + if (estimated == null) { + return scheduled; + } else { + return estimated.time; + } + } + record RealtimeEstimate(ZonedDateTime time, Duration scheduleOffset) {} } diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 7a1fcacbf31..0babb9a652f 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -279,10 +279,29 @@ public List getIntermediateStops() { for (int i = boardStopPosInPattern + 1; i < alightStopPosInPattern; i++) { StopLocation stop = tripPattern.getStop(i); + final var arrivalTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getArrivalTime(i) + ); + final var departureTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getDepartureTime(i) + ); + + var arrival = LegTimes.ofStatic(arrivalTime); + var departure = LegTimes.ofStatic(departureTime); + + if (getRealTime()) { + arrival = LegTimes.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTimes.of(departureTime, tripTimes.getDepartureDelay(i)); + } + StopArrival visit = new StopArrival( Place.forStop(stop), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, tripTimes.getArrivalTime(i)), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, tripTimes.getDepartureTime(i)), + arrival, + departure, i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 10398768c85..9f5f058ee86 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -1,55 +1,31 @@ package org.opentripplanner.model.plan; -import java.time.ZonedDateTime; import org.opentripplanner.framework.tostring.ToStringBuilder; /** * This class is used to represent a stop arrival event mostly for intermediate visits to a stops * along a route. + * + * @param arrival The time the rider will arrive at the place. + * @param departure The time the rider will depart the place. + * @param stopPosInPattern For transit trips, the stop index (numbered from zero from the start of + * the trip). + * @param gtfsStopSequence For transit trips, the sequence number of the stop. Per GTFS, these + * numbers are increasing. */ -public class StopArrival { - - public final Place place; - /** - * The time the rider will arrive at the place. - */ - public final ZonedDateTime arrival; - - /** - * The time the rider will depart the place. - */ - public final ZonedDateTime departure; - - /** - * For transit trips, the stop index (numbered from zero from the start of the trip). - */ - public final Integer stopPosInPattern; - - /** - * For transit trips, the sequence number of the stop. Per GTFS, these numbers are increasing. - */ - public final Integer gtfsStopSequence; - - public StopArrival( - Place place, - ZonedDateTime arrival, - ZonedDateTime departure, - Integer stopPosInPattern, - Integer gtfsStopSequence - ) { - this.place = place; - this.arrival = arrival; - this.departure = departure; - this.stopPosInPattern = stopPosInPattern; - this.gtfsStopSequence = gtfsStopSequence; - } - +public record StopArrival( + Place place, + LegTimes arrival, + LegTimes departure, + Integer stopPosInPattern, + Integer gtfsStopSequence +) { @Override public String toString() { return ToStringBuilder .of(StopArrival.class) - .addTime("arrival", arrival) - .addTime("departure", departure) + .addObj("arrival", arrival) + .addObj("departure", departure) .addObj("place", place) .toString(); } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java index dd08ab6095d..425bbf27e35 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java @@ -81,7 +81,7 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { if (leg.getIntermediateStops() != null) { Set stopConditions = StopCondition.PASSING; for (StopArrival visit : leg.getIntermediateStops()) { - if (visit.place.stop instanceof RegularStop stop) { + if (visit.place().stop instanceof RegularStop stop) { Collection alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions); alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions)); alerts.addAll( @@ -91,8 +91,8 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { ) ); - ZonedDateTime stopArrival = visit.arrival; - ZonedDateTime stopDeparture = visit.departure; + ZonedDateTime stopArrival = visit.arrival().time(); + ZonedDateTime stopDeparture = visit.departure().time(); addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture); } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index dc2f61133bf..4fd0a1c3d10 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2292,10 +2292,10 @@ type Place { lon: Float! "The time the rider will arrive at the place." - arrival: OffsetDateTime + arrival: LegTimes "The time the rider will depart the place." - departure: OffsetDateTime + departure: LegTimes """The stop related to the place.""" stop: Stop diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 5a76c7be06e..6090cdfbf48 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -89,8 +89,20 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:11:00Z", - "departure" : "2020-02-02T11:11:00Z", + "arrival" : { + "scheduled" : "2020-02-02T11:01:00Z", + "estimated" : { + "time" : "2020-02-02T11:11:00Z", + "scheduleOffset" : "PT10M" + } + }, + "departure" : { + "scheduled" : "2020-02-02T11:01:00Z", + "estimated" : { + "time" : "2020-02-02T11:11:00Z", + "scheduleOffset" : "PT10M" + } + }, "stop" : { "name" : "B" } @@ -139,8 +151,20 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:40:00Z", - "departure" : "2020-02-02T11:40:00Z", + "arrival" : { + "scheduled" : "2020-02-02T11:30:00Z", + "estimated" : { + "time" : "2020-02-02T11:40:00Z", + "scheduleOffset" : "PT10M" + } + }, + "departure" : { + "scheduled" : "2020-02-02T11:30:00Z", + "estimated" : { + "time" : "2020-02-02T11:40:00Z", + "scheduleOffset" : "PT10M" + } + }, "stop" : { "name" : "C" } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 8076a4887d3..a150bd8bf04 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -20,15 +20,25 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departure" : "2020-02-02T11:00:00Z", - "arrival" : "2020-02-02T11:00:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:00:00Z", + "estimated" : null + }, + "arrival" : { + "scheduled" : "2020-02-02T11:00:00Z", + "estimated" : null + } }, "to" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : "2020-02-02T11:00:20Z", - "arrival" : "2020-02-02T11:00:20Z" + "departure" : { + "scheduled" : "2020-02-02T11:00:20Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T11:00:20Z" + } }, "route" : null, "legGeometry" : null @@ -53,15 +63,31 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : "2020-02-02T11:01:00Z", - "arrival" : "2020-02-02T11:01:00Z" + "departure" : { + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } + }, + "arrival" : { + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } + } }, "to" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : "2020-02-02T11:15:00Z", - "arrival" : "2020-02-02T11:15:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:05:00Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T11:05:00Z" + } }, "route" : { "gtfsId" : "F:BUS", @@ -92,15 +118,31 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : "2020-02-02T11:30:00Z", - "arrival" : "2020-02-02T11:30:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } + }, + "arrival" : { + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } + } }, "to" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : "2020-02-02T11:50:00Z", - "arrival" : "2020-02-02T11:50:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:40:00Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T11:40:00Z" + } }, "route" : { "gtfsId" : "F:2", @@ -125,15 +167,25 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : "2020-02-02T11:50:00Z", - "arrival" : "2020-02-02T11:50:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:50:00Z", + "estimated" : null + }, + "arrival" : { + "scheduled" : "2020-02-02T11:50:00Z", + "estimated" : null + } }, "to" : { "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departure" : "2020-02-02T12:00:00Z", - "arrival" : "2020-02-02T12:00:00Z" + "departure" : { + "scheduled" : "2020-02-02T12:00:00Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T12:00:00Z" + } }, "route" : null, "legGeometry" : null diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index b805a94a3c2..e877e05ffe4 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -68,8 +68,20 @@ tripHeadsign } intermediatePlaces { - arrival - departure + arrival { + scheduled + estimated { + time + scheduleOffset + } + } + departure { + scheduled + estimated { + time + scheduleOffset + } + } stop { name } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 4bff431420c..4a9d7a174ba 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -39,15 +39,31 @@ name lat lon - departure - arrival + departure { + scheduled + estimated { + time + scheduleOffset + } + } + arrival { + scheduled + estimated { + time + scheduleOffset + } + } } to { name lat lon - departure - arrival + departure { + scheduled + } + arrival { + scheduled + } } route { gtfsId From b836c3b664a20d5ac0341c438cef2a7b1bafd110 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 13 Feb 2024 17:23:13 +0100 Subject: [PATCH 27/83] Apply review feedback --- .../impl/CombinedInterlinedTransitLeg.java | 6 +-- .../ext/flex/FlexibleTransitLeg.java | 10 ++--- .../apis/gtfs/datafetchers/LegImpl.java | 6 +-- .../apis/gtfs/datafetchers/PlaceImpl.java | 6 +-- .../gtfs/generated/GraphQLDataFetchers.java | 12 +++--- .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../model/plan/FrequencyTransitLeg.java | 4 +- .../org/opentripplanner/model/plan/Leg.java | 4 +- .../plan/{LegTimes.java => LegTimeEvent.java} | 12 +++--- .../model/plan/ScheduledTransitLeg.java | 20 +++++----- .../model/plan/StopArrival.java | 4 +- .../opentripplanner/model/plan/StreetLeg.java | 8 ++-- .../model/plan/UnknownTransitPathLeg.java | 8 ++-- .../opentripplanner/apis/gtfs/schema.graphqls | 38 +++++++++++++++---- 14 files changed, 81 insertions(+), 59 deletions(-) rename src/main/java/org/opentripplanner/model/plan/{LegTimes.java => LegTimeEvent.java} (56%) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 0b192a9ec77..27a9685b560 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -10,7 +10,7 @@ import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -58,12 +58,12 @@ public Trip getTrip() { } @Override - public LegTimes start() { + public LegTimeEvent start() { return first.start(); } @Override - public LegTimes end() { + public LegTimeEvent end() { return second.end(); } diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index 25caa9089e9..d793ad1956d 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,7 +16,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -86,13 +86,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimes start() { - return LegTimes.of(startTime, getArrivalDelay()); + public LegTimeEvent start() { + return LegTimeEvent.of(startTime, getArrivalDelay()); } @Override - public LegTimes end() { - return LegTimes.of(endTime, getDepartureDelay()); + public LegTimeEvent end() { + return LegTimeEvent.of(endTime, getDepartureDelay()); } @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 9a6076ecd08..7dc9492fbe3 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -18,7 +18,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,7 +79,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -223,7 +223,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 8d1434a033c..c4908b40aec 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -7,7 +7,7 @@ import org.opentripplanner.apis.gtfs.model.StopPosition; import org.opentripplanner.apis.gtfs.model.StopPosition.PositionAtStop; import org.opentripplanner.framework.graphql.GraphQLUtils; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.VertexType; @@ -19,7 +19,7 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> getSource(environment).arrival(); } @@ -54,7 +54,7 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> getSource(environment).departure(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index ec8556c45b0..e84ecfc20f4 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,7 +36,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -445,7 +445,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -487,7 +487,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -502,7 +502,7 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } - public interface GraphQLLegTimes { + public interface GraphQLLegTimeEvent { public DataFetcher estimated(); public DataFetcher scheduled(); @@ -591,7 +591,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -601,7 +601,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index ecc7a89fb44..fee61cee936 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -60,7 +60,7 @@ config: InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField Itinerary: org.opentripplanner.model.plan.Itinerary#Itinerary Leg: org.opentripplanner.model.plan.Leg#Leg - LegTimes: org.opentripplanner.model.plan.LegTimes#LegTimes + LegTimeEvent: org.opentripplanner.model.plan.LegTimeEvent#LegTimeEvent Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index 31ccbe31a53..0a620e6c681 100644 --- a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -55,8 +55,8 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), - LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), + LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), + LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 139d60b5171..cfb60519572 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,8 +200,8 @@ default Accessibility getTripWheelchairAccessibility() { return null; } - LegTimes start(); - LegTimes end(); + LegTimeEvent start(); + LegTimeEvent end(); /** * The date and time this leg begins. diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java similarity index 56% rename from src/main/java/org/opentripplanner/model/plan/LegTimes.java rename to src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java index 5e0802c6e4f..b5256429b1f 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java @@ -6,18 +6,18 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { - public LegTimes { +public record LegTimeEvent(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { + public LegTimeEvent { Objects.requireNonNull(scheduled); } @Nonnull - public static LegTimes of(ZonedDateTime realtime, int delaySecs) { + public static LegTimeEvent of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimes(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); + return new LegTimeEvent(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); } @Nonnull - public static LegTimes ofStatic(ZonedDateTime staticTime) { - return new LegTimes(staticTime, null); + public static LegTimeEvent ofStatic(ZonedDateTime staticTime) { + return new LegTimeEvent(staticTime, null); } public ZonedDateTime time() { diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 0babb9a652f..a537e9b81f8 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -163,20 +163,20 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimes start() { + public LegTimeEvent start() { if (getRealTime()) { - return LegTimes.of(startTime, getDepartureDelay()); + return LegTimeEvent.of(startTime, getDepartureDelay()); } else { - return LegTimes.ofStatic(startTime); + return LegTimeEvent.ofStatic(startTime); } } @Override - public LegTimes end() { + public LegTimeEvent end() { if (getRealTime()) { - return LegTimes.of(endTime, getArrivalDelay()); + return LegTimeEvent.of(endTime, getArrivalDelay()); } else { - return LegTimes.ofStatic(endTime); + return LegTimeEvent.ofStatic(endTime); } } @@ -290,12 +290,12 @@ public List getIntermediateStops() { tripTimes.getDepartureTime(i) ); - var arrival = LegTimes.ofStatic(arrivalTime); - var departure = LegTimes.ofStatic(departureTime); + var arrival = LegTimeEvent.ofStatic(arrivalTime); + var departure = LegTimeEvent.ofStatic(departureTime); if (getRealTime()) { - arrival = LegTimes.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = LegTimes.of(departureTime, tripTimes.getDepartureDelay(i)); + arrival = LegTimeEvent.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTimeEvent.of(departureTime, tripTimes.getDepartureDelay(i)); } StopArrival visit = new StopArrival( diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 9f5f058ee86..a1186fb4461 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -15,8 +15,8 @@ */ public record StopArrival( Place place, - LegTimes arrival, - LegTimes departure, + LegTimeEvent arrival, + LegTimeEvent departure, Integer stopPosInPattern, Integer gtfsStopSequence ) { diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 41062995cf4..372c987a5e4 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimes start() { - return LegTimes.ofStatic(startTime); + public LegTimeEvent start() { + return LegTimeEvent.ofStatic(startTime); } @Override - public LegTimes end() { - return LegTimes.ofStatic(endTime); + public LegTimeEvent end() { + return LegTimeEvent.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index 4dfefb086e3..8d1e1c134dd 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -69,13 +69,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimes start() { - return LegTimes.ofStatic(startTime); + public LegTimeEvent start() { + return LegTimeEvent.ofStatic(startTime); } @Override - public LegTimes end() { - return LegTimes.ofStatic(endTime); + public LegTimeEvent end() { + return LegTimeEvent.ofStatic(endTime); } @Override diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 4fd0a1c3d10..4b43dc091e5 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1497,7 +1497,10 @@ type DefaultFareProduct implements FareProduct { } type Itinerary { + "Time when the user leaves from the origin." start: OffsetDateTime + + "Time when the user leaves arrives at the destination." end: OffsetDateTime """Duration of the trip on this itinerary, in seconds.""" @@ -1662,15 +1665,28 @@ type RealtimeEstimate { scheduleOffset: Duration } -type LegTimes { - scheduled: OffsetDateTime +""" +Time information about a passenger at a certain place. May contain real-time information if +available. +""" +type LegTimeEvent { + "The scheduled time of the event." + scheduled: OffsetDateTime! + "The estimated time of the event, if available." estimated: RealtimeEstimate } type Leg { - start: LegTimes - end: LegTimes + """ + The time when the leg starts including real-time information, if available. + """ + start: LegTimeEvent + + """ + The time when the leg ends including real-time information, if available. + """ + end: LegTimeEvent """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode @@ -2291,11 +2307,17 @@ type Place { """Longitude of the place (WGS 84)""" lon: Float! - "The time the rider will arrive at the place." - arrival: LegTimes + """ + The time the rider will arrive at the place. This also includes real-time information + if available. + """ + arrival: LegTimeEvent - "The time the rider will depart the place." - departure: LegTimes + """ + The time the rider will depart the place. This also includes real-time information + if available. + """ + departure: LegTimeEvent """The stop related to the place.""" stop: Stop From bf7dc55191a5cfcd24c853b703769120ccf51eaa Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 14 Feb 2024 08:11:44 +0100 Subject: [PATCH 28/83] Implement OffsetDateTimeParser --- .../apis/gtfs/GraphQLScalars.java | 39 ++++++++++++---- .../model/scalars/DateTimeScalarFactory.java | 19 +------- .../framework/time/OffsetDateTimeParser.java | 42 +++++++++++++++++ .../time/OffsetDateTimeParserTest.java | 45 +++++++++++++++++++ 4 files changed, 120 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java create mode 100644 src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 3e376b60b35..82ef8090d86 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -18,6 +18,7 @@ import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.graphql.scalar.DurationScalarFactory; import org.opentripplanner.framework.model.Grams; +import org.opentripplanner.framework.time.OffsetDateTimeParser; public class GraphQLScalars { @@ -25,7 +26,7 @@ public class GraphQLScalars { .registerModule(new JtsModule(GeometryUtils.getGeometryFactory())); public static GraphQLScalarType durationScalar = DurationScalarFactory.createDurationScalar(); - public static GraphQLScalarType polylineScalar = GraphQLScalarType + public static final GraphQLScalarType polylineScalar = GraphQLScalarType .newScalar() .name("Polyline") .description( @@ -54,7 +55,7 @@ public String parseLiteral(Object input) { ) .build(); - public static GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType + public static final GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType .newScalar() .name("OffsetDateTime") .coercing( @@ -66,23 +67,45 @@ public String serialize(@Nonnull Object dataFetcherResult) return zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); } else if (dataFetcherResult instanceof OffsetDateTime odt) { return odt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); - } else return null; + } else { + throw new CoercingSerializeException( + "Cannot serialize object of class %s".formatted( + dataFetcherResult.getClass().getSimpleName() + ) + ); + } } @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { - return null; + if (input instanceof CharSequence cs) { + return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); + } + throw valueException(input); } @Override public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { - return null; + if (input instanceof StringValue sv) { + return OffsetDateTimeParser + .parseLeniently(sv.getValue()) + .orElseThrow(() -> literalException(input)); + } + throw literalException(input); + } + + private static CoercingParseValueException valueException(Object input) { + return new CoercingParseValueException("Cannot parse %s".formatted(input)); + } + + private static CoercingParseLiteralException literalException(Object input) { + return new CoercingParseLiteralException("Cannot parse %s".formatted(input)); } } ) .build(); - public static GraphQLScalarType geoJsonScalar = GraphQLScalarType + public static final GraphQLScalarType geoJsonScalar = GraphQLScalarType .newScalar() .name("GeoJson") .description("Geographic data structures in JSON format. See: https://geojson.org/") @@ -110,7 +133,7 @@ public Geometry parseLiteral(Object input) throws CoercingParseLiteralException ) .build(); - public static GraphQLScalarType graphQLIDScalar = GraphQLScalarType + public static final GraphQLScalarType graphQLIDScalar = GraphQLScalarType .newScalar() .name("ID") .coercing( @@ -150,7 +173,7 @@ public Relay.ResolvedGlobalId parseLiteral(Object input) ) .build(); - public static GraphQLScalarType gramsScalar = GraphQLScalarType + public static final GraphQLScalarType gramsScalar = GraphQLScalarType .newScalar() .name("Grams") .coercing( diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java index 706adc81704..9738a277a41 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java @@ -10,10 +10,10 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; import javax.annotation.Nonnull; +import org.opentripplanner.framework.time.OffsetDateTimeParser; public final class DateTimeScalarFactory { @@ -25,22 +25,7 @@ public final class DateTimeScalarFactory { Example: `2017-04-23T18:25:43+02:00` or `2017-04-23T16:25:43Z`"""; - // We need to have two offsets, in order to parse both "+0200" and "+02:00". The first is not - // really ISO-8601 compatible with the extended date and time. We need to make parsing strict, in - // order to keep the minute mandatory, otherwise we would be left with an unparsed minute - private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .parseLenient() - .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME) - .optionalStart() - .parseStrict() - .appendOffset("+HH:MM:ss", "Z") - .parseLenient() - .optionalEnd() - .optionalStart() - .appendOffset("+HHmmss", "Z") - .optionalEnd() - .toFormatter(); + private static final DateTimeFormatter PARSER = OffsetDateTimeParser.LENIENT_PARSER; private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_OFFSET_DATE_TIME; diff --git a/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java new file mode 100644 index 00000000000..11652d797a7 --- /dev/null +++ b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java @@ -0,0 +1,42 @@ +package org.opentripplanner.framework.time; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.util.Optional; + +public class OffsetDateTimeParser { + + /** + * We need to have two offsets, in order to parse both "+0200" and "+02:00". The first is not + * really ISO-8601 compatible with the extended date and time. We need to make parsing strict, in + * order to keep the minute mandatory, otherwise we would be left with an unparsed minute + */ + public static final DateTimeFormatter LENIENT_PARSER = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .parseLenient() + .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + .optionalStart() + .parseStrict() + .appendOffset("+HH:MM:ss", "Z") + .parseLenient() + .optionalEnd() + .optionalStart() + .appendOffset("+HHmmss", "Z") + .optionalEnd() + .toFormatter(); + + /** + * Parses a ISO-8601 string into am OffsetDateTime instance allowing the offset to be both in + * '02:00' and '0200' format. + */ + public static Optional parseLeniently(CharSequence input) { + try { + var result = OffsetDateTime.parse(input, LENIENT_PARSER); + return Optional.of(result); + } catch (DateTimeParseException e) { + return Optional.empty(); + } + } +} diff --git a/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java new file mode 100644 index 00000000000..1f164ada783 --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java @@ -0,0 +1,45 @@ +package org.opentripplanner.framework.time; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.OffsetDateTime; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class OffsetDateTimeParserTest { + + private static final String TIME_STRING = "2023-01-27T12:59:00+01:00"; + private static final OffsetDateTime TIME = OffsetDateTime.parse(TIME_STRING); + + static List successfulCases() { + return List.of( + TIME_STRING, + "2023-01-27T12:59:00.000+01:00", + "2023-01-27T12:59:00+0100", + "2023-01-27T12:59:00+01", + "2023-01-27T11:59:00Z", + "2023-01-27T11:59Z", + "2023-01-27T06:59:00-05:00", + "2023-01-27T06:59:00-0500" + ); + } + + @ParameterizedTest + @MethodSource("successfulCases") + void parse(String input) { + var res = OffsetDateTimeParser.parseLeniently(input); + assertTrue(res.get().isEqual(TIME)); + } + + static List failedCases() { + return List.of("2023-01-27T11:59:00", "2023-01-27T11", "2023-01-27T11:00"); + } + + @ParameterizedTest + @MethodSource("failedCases") + void failed(String input) { + var res = OffsetDateTimeParser.parseLeniently(input); + assertTrue(res.isEmpty()); + } +} From 6cb475c4f701c96f4c9dc3cca13d35b9d82393f0 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 11:26:00 +0100 Subject: [PATCH 29/83] Revert to 'LegTime' --- .../impl/CombinedInterlinedTransitLeg.java | 6 +++--- .../ext/flex/FlexibleTransitLeg.java | 10 +++++----- .../apis/gtfs/datafetchers/LegImpl.java | 6 +++--- .../apis/gtfs/datafetchers/PlaceImpl.java | 6 +++--- .../gtfs/generated/GraphQLDataFetchers.java | 16 +++++++++------ .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../model/plan/FrequencyTransitLeg.java | 4 ++-- .../org/opentripplanner/model/plan/Leg.java | 4 ++-- .../plan/{LegTimeEvent.java => LegTime.java} | 15 ++++++++------ .../model/plan/ScheduledTransitLeg.java | 20 +++++++++---------- .../model/plan/StopArrival.java | 4 ++-- .../opentripplanner/model/plan/StreetLeg.java | 8 ++++---- .../model/plan/UnknownTransitPathLeg.java | 8 ++++---- .../opentripplanner/apis/gtfs/schema.graphqls | 10 +++++----- 14 files changed, 63 insertions(+), 56 deletions(-) rename src/main/java/org/opentripplanner/model/plan/{LegTimeEvent.java => LegTime.java} (52%) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 27a9685b560..9d10b87bbd6 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -10,7 +10,7 @@ import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -58,12 +58,12 @@ public Trip getTrip() { } @Override - public LegTimeEvent start() { + public LegTime start() { return first.start(); } @Override - public LegTimeEvent end() { + public LegTime end() { return second.end(); } diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index d793ad1956d..e0bdb6cc899 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,7 +16,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -86,13 +86,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimeEvent start() { - return LegTimeEvent.of(startTime, getArrivalDelay()); + public LegTime start() { + return LegTime.of(startTime, getArrivalDelay()); } @Override - public LegTimeEvent end() { - return LegTimeEvent.of(endTime, getDepartureDelay()); + public LegTime end() { + return LegTime.of(endTime, getDepartureDelay()); } @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 7dc9492fbe3..f7be76481a7 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -18,7 +18,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,7 +79,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -223,7 +223,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index c4908b40aec..16716a393d1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -7,7 +7,7 @@ import org.opentripplanner.apis.gtfs.model.StopPosition; import org.opentripplanner.apis.gtfs.model.StopPosition.PositionAtStop; import org.opentripplanner.framework.graphql.GraphQLUtils; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.VertexType; @@ -19,7 +19,7 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> getSource(environment).arrival(); } @@ -54,7 +54,7 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> getSource(environment).departure(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index e84ecfc20f4..3b4f7889cb4 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,7 +36,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -445,7 +445,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -487,7 +487,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -502,7 +502,11 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } - public interface GraphQLLegTimeEvent { + /** + * Time information about a passenger at a certain place. May contain real-time information if + * available. + */ + public interface GraphQLLegTime { public DataFetcher estimated(); public DataFetcher scheduled(); @@ -591,7 +595,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -601,7 +605,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index fee61cee936..55f76863cc6 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -60,7 +60,7 @@ config: InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField Itinerary: org.opentripplanner.model.plan.Itinerary#Itinerary Leg: org.opentripplanner.model.plan.Leg#Leg - LegTimeEvent: org.opentripplanner.model.plan.LegTimeEvent#LegTimeEvent + LegTime: org.opentripplanner.model.plan.LegTime#LegTime Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index 0a620e6c681..48c4b1b7b87 100644 --- a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -55,8 +55,8 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), - LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), + LegTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), + LegTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index cfb60519572..e2d7d951556 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,8 +200,8 @@ default Accessibility getTripWheelchairAccessibility() { return null; } - LegTimeEvent start(); - LegTimeEvent end(); + LegTime start(); + LegTime end(); /** * The date and time this leg begins. diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java similarity index 52% rename from src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java rename to src/main/java/org/opentripplanner/model/plan/LegTime.java index b5256429b1f..c0b76b7486a 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -6,18 +6,21 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimeEvent(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { - public LegTimeEvent { +/** + * A scheduled time of a transit vehicle at a certain location with a optional realtime information. + */ +public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { + public LegTime { Objects.requireNonNull(scheduled); } @Nonnull - public static LegTimeEvent of(ZonedDateTime realtime, int delaySecs) { + public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimeEvent(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); + return new LegTime(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); } @Nonnull - public static LegTimeEvent ofStatic(ZonedDateTime staticTime) { - return new LegTimeEvent(staticTime, null); + public static LegTime ofStatic(ZonedDateTime staticTime) { + return new LegTime(staticTime, null); } public ZonedDateTime time() { diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index a537e9b81f8..a4050fc3cb2 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -163,20 +163,20 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimeEvent start() { + public LegTime start() { if (getRealTime()) { - return LegTimeEvent.of(startTime, getDepartureDelay()); + return LegTime.of(startTime, getDepartureDelay()); } else { - return LegTimeEvent.ofStatic(startTime); + return LegTime.ofStatic(startTime); } } @Override - public LegTimeEvent end() { + public LegTime end() { if (getRealTime()) { - return LegTimeEvent.of(endTime, getArrivalDelay()); + return LegTime.of(endTime, getArrivalDelay()); } else { - return LegTimeEvent.ofStatic(endTime); + return LegTime.ofStatic(endTime); } } @@ -290,12 +290,12 @@ public List getIntermediateStops() { tripTimes.getDepartureTime(i) ); - var arrival = LegTimeEvent.ofStatic(arrivalTime); - var departure = LegTimeEvent.ofStatic(departureTime); + var arrival = LegTime.ofStatic(arrivalTime); + var departure = LegTime.ofStatic(departureTime); if (getRealTime()) { - arrival = LegTimeEvent.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = LegTimeEvent.of(departureTime, tripTimes.getDepartureDelay(i)); + arrival = LegTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTime.of(departureTime, tripTimes.getDepartureDelay(i)); } StopArrival visit = new StopArrival( diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index a1186fb4461..8a6b55c9346 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -15,8 +15,8 @@ */ public record StopArrival( Place place, - LegTimeEvent arrival, - LegTimeEvent departure, + LegTime arrival, + LegTime departure, Integer stopPosInPattern, Integer gtfsStopSequence ) { diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 372c987a5e4..6384159a4ec 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimeEvent start() { - return LegTimeEvent.ofStatic(startTime); + public LegTime start() { + return LegTime.ofStatic(startTime); } @Override - public LegTimeEvent end() { - return LegTimeEvent.ofStatic(endTime); + public LegTime end() { + return LegTime.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index 8d1e1c134dd..df43bbcb411 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -69,13 +69,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimeEvent start() { - return LegTimeEvent.ofStatic(startTime); + public LegTime start() { + return LegTime.ofStatic(startTime); } @Override - public LegTimeEvent end() { - return LegTimeEvent.ofStatic(endTime); + public LegTime end() { + return LegTime.ofStatic(endTime); } @Override diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 4b43dc091e5..1b1897c5091 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1669,7 +1669,7 @@ type RealtimeEstimate { Time information about a passenger at a certain place. May contain real-time information if available. """ -type LegTimeEvent { +type LegTime { "The scheduled time of the event." scheduled: OffsetDateTime! "The estimated time of the event, if available." @@ -1681,12 +1681,12 @@ type Leg { """ The time when the leg starts including real-time information, if available. """ - start: LegTimeEvent + start: LegTime """ The time when the leg ends including real-time information, if available. """ - end: LegTimeEvent + end: LegTime """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode @@ -2311,13 +2311,13 @@ type Place { The time the rider will arrive at the place. This also includes real-time information if available. """ - arrival: LegTimeEvent + arrival: LegTime """ The time the rider will depart the place. This also includes real-time information if available. """ - departure: LegTimeEvent + departure: LegTime """The stop related to the place.""" stop: Stop From 2130da9590ee39926ee828bb5142a012472b8046 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 11:56:51 +0100 Subject: [PATCH 30/83] Rename fields --- .../gtfs/generated/GraphQLDataFetchers.java | 4 +- .../opentripplanner/model/plan/LegTime.java | 16 ++- .../algorithm/mapping/AlertToLegMapper.java | 4 +- .../opentripplanner/apis/gtfs/schema.graphqls | 6 +- .../apis/gtfs/expectations/plan-extended.json | 128 +++++++++++++++--- .../apis/gtfs/expectations/plan.json | 104 ++++++-------- .../apis/gtfs/queries/plan-extended.graphql | 44 ++++-- .../apis/gtfs/queries/plan.graphql | 34 ++--- 8 files changed, 217 insertions(+), 123 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 3b4f7889cb4..7fab5720b9a 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -509,7 +509,7 @@ public interface GraphQLLeg { public interface GraphQLLegTime { public DataFetcher estimated(); - public DataFetcher scheduled(); + public DataFetcher scheduledTime(); } /** A span of time. */ @@ -764,7 +764,7 @@ public interface GraphQLQueryType { } public interface GraphQLRealtimeEstimate { - public DataFetcher scheduleOffset(); + public DataFetcher delay(); public DataFetcher time(); } diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index c0b76b7486a..2dc97b92a11 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -9,9 +9,9 @@ /** * A scheduled time of a transit vehicle at a certain location with a optional realtime information. */ -public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { +public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealtimeEstimate estimated) { public LegTime { - Objects.requireNonNull(scheduled); + Objects.requireNonNull(scheduledTime); } @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { @@ -23,13 +23,21 @@ public static LegTime ofStatic(ZonedDateTime staticTime) { return new LegTime(staticTime, null); } + /** + * The most up-to-date time available: if realtime data is available it is returned, if not then + * the scheduled one is. + */ public ZonedDateTime time() { if (estimated == null) { - return scheduled; + return scheduledTime; } else { return estimated.time; } } - record RealtimeEstimate(ZonedDateTime time, Duration scheduleOffset) {} + /** + * Realtime information about a vehicle at a certain place. + * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. + */ + record RealtimeEstimate(ZonedDateTime time, Duration delay) {} } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java index 425bbf27e35..4b2b194fbe4 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java @@ -91,8 +91,8 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { ) ); - ZonedDateTime stopArrival = visit.arrival().time(); - ZonedDateTime stopDeparture = visit.departure().time(); + ZonedDateTime stopArrival = visit.arrival().scheduledTime(); + ZonedDateTime stopDeparture = visit.departure().scheduledTime(); addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture); } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 1b1897c5091..2f3e2862c01 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1656,13 +1656,13 @@ ISO-8601 allows many different formats but OTP will only return the profile spec scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") type RealtimeEstimate { - time: OffsetDateTime + time: OffsetDateTime! """ The delay or "earliness" of the vehicle at a certain place. If the vehicle is early then this is a negative duration. """ - scheduleOffset: Duration + delay: Duration! } """ @@ -1671,7 +1671,7 @@ available. """ type LegTime { "The scheduled time of the event." - scheduled: OffsetDateTime! + scheduledTime: OffsetDateTime! "The estimated time of the event, if available." estimated: RealtimeEstimate } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 6090cdfbf48..bfb6d969cc7 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -19,17 +19,25 @@ { "mode" : "WALK", "start" : { - "scheduled" : "2020-02-02T11:00:00Z", + "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, "end" : { - "scheduled" : "2020-02-02T11:00:20Z", + "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, "from" : { "name" : "A", "lat" : 5.0, "lon" : 8.0, + "departure" : { + "scheduledTime" : "2020-02-02T11:00:00Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:00:00Z", + "estimated" : null + }, "departureTime" : 1580641200000, "arrivalTime" : 1580641200000 }, @@ -37,6 +45,14 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, + "departure" : { + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null + }, "departureTime" : 1580641220000, "arrivalTime" : 1580641220000 }, @@ -53,23 +69,37 @@ { "mode" : "BUS", "start" : { - "scheduled" : "2020-02-02T10:51:00Z", + "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "end" : { - "scheduled" : "2020-02-02T11:05:00Z", + "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "time" : "2020-02-02T11:15:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "from" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, + "departure" : { + "scheduledTime" : "2020-02-02T10:51:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:01:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T10:51:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:01:00Z" + } + }, "departureTime" : 1580641260000, "arrivalTime" : 1580641260000 }, @@ -77,6 +107,20 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, + "departure" : { + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:15:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:15:00Z" + } + }, "departureTime" : 1580642100000, "arrivalTime" : 1580642100000 }, @@ -90,17 +134,17 @@ "intermediatePlaces" : [ { "arrival" : { - "scheduled" : "2020-02-02T11:01:00Z", + "scheduledTime" : "2020-02-02T11:01:00Z", "estimated" : { "time" : "2020-02-02T11:11:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "departure" : { - "scheduled" : "2020-02-02T11:01:00Z", + "scheduledTime" : "2020-02-02T11:01:00Z", "estimated" : { "time" : "2020-02-02T11:11:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "stop" : { @@ -115,23 +159,37 @@ { "mode" : "RAIL", "start" : { - "scheduled" : "2020-02-02T11:20:00Z", + "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "end" : { - "scheduled" : "2020-02-02T11:40:00Z", + "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "time" : "2020-02-02T11:50:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "from" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, + "departure" : { + "scheduledTime" : "2020-02-02T11:20:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:30:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:20:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:30:00Z" + } + }, "departureTime" : 1580643000000, "arrivalTime" : 1580643000000 }, @@ -139,6 +197,20 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, + "departure" : { + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:50:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:50:00Z" + } + }, "departureTime" : 1580644200000, "arrivalTime" : 1580644200000 }, @@ -152,17 +224,17 @@ "intermediatePlaces" : [ { "arrival" : { - "scheduled" : "2020-02-02T11:30:00Z", + "scheduledTime" : "2020-02-02T11:30:00Z", "estimated" : { "time" : "2020-02-02T11:40:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "departure" : { - "scheduled" : "2020-02-02T11:30:00Z", + "scheduledTime" : "2020-02-02T11:30:00Z", "estimated" : { "time" : "2020-02-02T11:40:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "stop" : { @@ -197,17 +269,25 @@ { "mode" : "CAR", "start" : { - "scheduled" : "2020-02-02T11:50:00Z", + "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, "end" : { - "scheduled" : "2020-02-02T12:00:00Z", + "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, "from" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, + "departure" : { + "scheduledTime" : "2020-02-02T11:50:00Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:50:00Z", + "estimated" : null + }, "departureTime" : 1580644200000, "arrivalTime" : 1580644200000 }, @@ -215,6 +295,14 @@ "name" : "E", "lat" : 9.0, "lon" : 10.0, + "departure" : { + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null + }, "departureTime" : 1580644800000, "arrivalTime" : 1580644800000 }, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index a150bd8bf04..72d0cc017fe 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -8,24 +8,16 @@ "legs" : [ { "mode" : "WALK", - "start" : { - "scheduled" : "2020-02-02T11:00:00Z", - "estimated" : null - }, - "end" : { - "scheduled" : "2020-02-02T11:00:20Z", - "estimated" : null - }, "from" : { "name" : "A", "lat" : 5.0, "lon" : 8.0, "departure" : { - "scheduled" : "2020-02-02T11:00:00Z", + "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T11:00:00Z", + "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null } }, @@ -34,10 +26,12 @@ "lat" : 6.0, "lon" : 8.5, "departure" : { - "scheduled" : "2020-02-02T11:00:20Z" + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T11:00:20Z" + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null } }, "route" : null, @@ -45,36 +39,22 @@ }, { "mode" : "BUS", - "start" : { - "scheduled" : "2020-02-02T10:51:00Z", - "estimated" : { - "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" - } - }, - "end" : { - "scheduled" : "2020-02-02T11:05:00Z", - "estimated" : { - "time" : "2020-02-02T11:15:00Z", - "scheduleOffset" : "PT10M" - } - }, "from" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, "departure" : { - "scheduled" : "2020-02-02T10:51:00Z", + "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "arrival" : { - "scheduled" : "2020-02-02T10:51:00Z", + "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } } }, @@ -83,10 +63,18 @@ "lat" : 7.0, "lon" : 9.0, "departure" : { - "scheduled" : "2020-02-02T11:05:00Z" + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "delay" : "PT10M" + } }, "arrival" : { - "scheduled" : "2020-02-02T11:05:00Z" + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "delay" : "PT10M" + } } }, "route" : { @@ -100,36 +88,22 @@ }, { "mode" : "RAIL", - "start" : { - "scheduled" : "2020-02-02T11:20:00Z", - "estimated" : { - "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" - } - }, - "end" : { - "scheduled" : "2020-02-02T11:40:00Z", - "estimated" : { - "time" : "2020-02-02T11:50:00Z", - "scheduleOffset" : "PT10M" - } - }, "from" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, "departure" : { - "scheduled" : "2020-02-02T11:20:00Z", + "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "arrival" : { - "scheduled" : "2020-02-02T11:20:00Z", + "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } } }, @@ -138,10 +112,18 @@ "lat" : 8.0, "lon" : 9.5, "departure" : { - "scheduled" : "2020-02-02T11:40:00Z" + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "delay" : "PT10M" + } }, "arrival" : { - "scheduled" : "2020-02-02T11:40:00Z" + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "delay" : "PT10M" + } } }, "route" : { @@ -155,24 +137,16 @@ }, { "mode" : "CAR", - "start" : { - "scheduled" : "2020-02-02T11:50:00Z", - "estimated" : null - }, - "end" : { - "scheduled" : "2020-02-02T12:00:00Z", - "estimated" : null - }, "from" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, "departure" : { - "scheduled" : "2020-02-02T11:50:00Z", + "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T11:50:00Z", + "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null } }, @@ -181,10 +155,12 @@ "lat" : 9.0, "lon" : 10.0, "departure" : { - "scheduled" : "2020-02-02T12:00:00Z" + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T12:00:00Z" + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null } }, "route" : null, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index e877e05ffe4..dcec1a1026c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -32,23 +32,37 @@ legs { mode start { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } end { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } from { name lat lon + departure { + scheduledTime + estimated { + delay + time + } + } + arrival { + scheduledTime + estimated { + delay + time + } + } departureTime arrivalTime } @@ -56,6 +70,20 @@ name lat lon + departure { + scheduledTime + estimated { + delay + time + } + } + arrival { + scheduledTime + estimated { + delay + time + } + } departureTime arrivalTime } @@ -69,17 +97,17 @@ } intermediatePlaces { arrival { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } departure { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } stop { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 4a9d7a174ba..635b9f1531a 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -21,36 +21,22 @@ end legs { mode - start { - scheduled - estimated { - time - scheduleOffset - } - } - end { - scheduled - estimated { - time - scheduleOffset - } - } from { name lat lon departure { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } arrival { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } } @@ -59,10 +45,18 @@ lat lon departure { - scheduled + scheduledTime + estimated { + time + delay + } } arrival { - scheduled + scheduledTime + estimated { + time + delay + } } } route { From 8b37735a018140d703b40f53838b44a7df0cde48 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 12:04:45 +0100 Subject: [PATCH 31/83] Improve scalars --- docs/apis/GraphQL-Tutorial.md | 34 +++++----- magidoc.mjs | 2 +- .../apis/gtfs/GraphQLScalars.java | 18 ++---- .../apis/gtfs/GraphQLScalarsTest.java | 62 +++++++++++++------ 4 files changed, 63 insertions(+), 53 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 863aa8bd57c..1a56d02b6ca 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -92,36 +92,22 @@ Most people want to get routing results out of OTP, so lets see the query for th end legs { mode - start { - scheduled - estimated { - time - scheduleOffset - } - } - end { - scheduled - estimated { - time - scheduleOffset - } - } from { name lat lon departure { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } arrival { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } } @@ -130,10 +116,18 @@ Most people want to get routing results out of OTP, so lets see the query for th lat lon departure { - scheduled + scheduledTime + estimated { + time + delay + } } arrival { - scheduled + scheduledTime + estimated { + time + delay + } } } route { diff --git a/magidoc.mjs b/magidoc.mjs index bb138f3c87d..a57b17a4308 100644 --- a/magidoc.mjs +++ b/magidoc.mjs @@ -36,7 +36,7 @@ To learn how to deactivate it, read the queryGenerationFactories: { 'Polyline': '<>', 'GeoJson': '<>', - 'OffsetDateTime': '2024-02-05T18:04:23+0100' + 'OffsetDateTime': '2024-02-05T18:04:23+01:00' }, } }, diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 82ef8090d86..e6ab9f7dd5d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -79,9 +79,11 @@ public String serialize(@Nonnull Object dataFetcherResult) @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { if (input instanceof CharSequence cs) { - return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); + return OffsetDateTimeParser + .parseLeniently(cs) + .orElseThrow(CoercingParseValueException::new); } - throw valueException(input); + throw new CoercingParseValueException(); } @Override @@ -89,17 +91,9 @@ public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralExce if (input instanceof StringValue sv) { return OffsetDateTimeParser .parseLeniently(sv.getValue()) - .orElseThrow(() -> literalException(input)); + .orElseThrow(CoercingParseLiteralException::new); } - throw literalException(input); - } - - private static CoercingParseValueException valueException(Object input) { - return new CoercingParseValueException("Cannot parse %s".formatted(input)); - } - - private static CoercingParseLiteralException literalException(Object input) { - return new CoercingParseLiteralException("Cannot parse %s".formatted(input)); + throw new CoercingParseLiteralException(); } } ) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 079749f3ccc..652c72254d9 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.params.provider.Arguments.of; import com.fasterxml.jackson.core.JsonProcessingException; +import graphql.language.StringValue; import graphql.schema.CoercingSerializeException; import java.time.Duration; import java.time.LocalDate; @@ -12,6 +13,7 @@ import java.time.ZoneOffset; import java.util.List; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -23,7 +25,7 @@ class GraphQLScalarsTest { - private static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( + static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( LocalDate.of(2024, 2, 4), LocalTime.MIDNIGHT, ZoneOffset.UTC @@ -71,25 +73,45 @@ void geoJson() throws JsonProcessingException { assertEquals(jsonNode.toString(), geoJson.toString()); } - static List offsetDateTimeCases() { - return List.of( - of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), - of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), - "2024-02-04T01:00:00+01:00" - ), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), - "2024-02-03T19:00:00-05:00" - ) - ); - } + @Nested + class OffsetDateTimeTests { - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void duration(OffsetDateTime odt, String expected) { - var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); - assertEquals(expected, string); + static List offsetDateTimeCases() { + return List.of( + of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), + of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), + "2024-02-04T01:00:00+01:00" + ), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), + "2024-02-03T19:00:00-05:00" + ) + ); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void serializeOffsetDateTime(OffsetDateTime odt, String expected) { + var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + assertEquals(expected, string); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTime(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); + assertEquals(expected, odt); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar + .getCoercing() + .parseLiteral(new StringValue(input)); + assertEquals(expected, odt); + } } } From 4d295da420d2b7d1fb4fabcd88d5c5829a32a3c7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 14:08:52 +0100 Subject: [PATCH 32/83] Throw exception in scalar again --- .../opentripplanner/apis/gtfs/GraphQLScalars.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index e6ab9f7dd5d..7d70f4be3b5 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -79,11 +79,9 @@ public String serialize(@Nonnull Object dataFetcherResult) @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { if (input instanceof CharSequence cs) { - return OffsetDateTimeParser - .parseLeniently(cs) - .orElseThrow(CoercingParseValueException::new); + return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); } - throw new CoercingParseValueException(); + throw valueException(input); } @Override @@ -95,6 +93,12 @@ public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralExce } throw new CoercingParseLiteralException(); } + + private static CoercingParseValueException valueException(Object input) { + return new CoercingParseValueException( + "Cannot parse %s into an OffsetDateTime.".formatted(input) + ); + } } ) .build(); From 92c7acd14e5b204c1d82d21ee35c5a2583f246a5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 07:16:51 +0100 Subject: [PATCH 33/83] Switch order of arrival, departure --- docs/apis/GraphQL-Tutorial.md | 8 ++--- .../apis/gtfs/expectations/plan-extended.json | 32 +++++++++---------- .../apis/gtfs/expectations/plan.json | 32 +++++++++---------- .../apis/gtfs/queries/plan-extended.graphql | 8 ++--- .../apis/gtfs/queries/plan.graphql | 8 ++--- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 1a56d02b6ca..7e1f6b0f6db 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -96,14 +96,14 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time @@ -115,14 +115,14 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index bfb6d969cc7..ea58480be8e 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -30,11 +30,11 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, @@ -45,11 +45,11 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, @@ -86,14 +86,14 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:01:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "delay" : "PT10M", @@ -107,14 +107,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:15:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "delay" : "PT10M", @@ -176,14 +176,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:30:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "delay" : "PT10M", @@ -197,14 +197,14 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:50:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "delay" : "PT10M", @@ -280,11 +280,11 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, @@ -295,11 +295,11 @@ "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 72d0cc017fe..ec971af5b3c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -12,11 +12,11 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null } @@ -25,11 +25,11 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null } @@ -43,14 +43,14 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", @@ -62,14 +62,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "time" : "2020-02-02T11:15:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "time" : "2020-02-02T11:15:00Z", @@ -92,14 +92,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", @@ -111,14 +111,14 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "time" : "2020-02-02T11:50:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "time" : "2020-02-02T11:50:00Z", @@ -141,11 +141,11 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null } @@ -154,11 +154,11 @@ "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index dcec1a1026c..bcd96892e84 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -49,14 +49,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { delay time } } - arrival { + departure { scheduledTime estimated { delay @@ -70,14 +70,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { delay time } } - arrival { + departure { scheduledTime estimated { delay diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 635b9f1531a..cc93ffb211c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -25,14 +25,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time @@ -44,14 +44,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time From 39f06dcc5cf026317674917a30de66d53c0bb8e7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 07:32:05 +0100 Subject: [PATCH 34/83] Add documentation --- src/main/java/org/opentripplanner/model/plan/Leg.java | 7 +++++++ .../org/opentripplanner/apis/gtfs/schema.graphqls | 7 ++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index e2d7d951556..0063ecf87c2 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,7 +200,14 @@ default Accessibility getTripWheelchairAccessibility() { return null; } + /** + * The time (including realtime information) when the leg starts. + */ LegTime start(); + + /** + * The time (including realtime information) when the leg ends.. + */ LegTime end(); /** diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2f3e2862c01..93de5101451 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1655,6 +1655,7 @@ ISO-8601 allows many different formats but OTP will only return the profile spec """ scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") +"Real-time estimates for a vehicle at a certain place." type RealtimeEstimate { time: OffsetDateTime! """ @@ -1672,7 +1673,7 @@ available. type LegTime { "The scheduled time of the event." scheduledTime: OffsetDateTime! - "The estimated time of the event, if available." + "The estimated time of the event. If no real-time information is available, this is null," estimated: RealtimeEstimate } @@ -1681,12 +1682,12 @@ type Leg { """ The time when the leg starts including real-time information, if available. """ - start: LegTime + start: LegTime! """ The time when the leg ends including real-time information, if available. """ - end: LegTime + end: LegTime! """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode From b4707ed4c635f2451b3741212e8dbdc61eeef8b8 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 09:00:33 +0100 Subject: [PATCH 35/83] Add test for leg times --- .../model/plan/ScheduledTransitLegTest.java | 65 +++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java b/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java index e45beb8ebad..b41ace81e8d 100644 --- a/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java +++ b/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java @@ -1,6 +1,8 @@ package org.opentripplanner.model.plan; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.opentripplanner.transit.model._data.TransitModelForTest.id; import java.time.OffsetDateTime; @@ -9,33 +11,74 @@ import org.junit.jupiter.api.Test; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; +import org.opentripplanner.transit.model.timetable.ScheduledTripTimes; +import org.opentripplanner.transit.model.timetable.Trip; class ScheduledTransitLegTest { static final ZonedDateTime TIME = OffsetDateTime .parse("2023-04-17T17:49:06+02:00") .toZonedDateTime(); + private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final Route ROUTE = TransitModelForTest.route(id("2")).build(); + private static final TripPattern PATTERN = TransitModelForTest + .tripPattern("1", ROUTE) + .withStopPattern(TEST_MODEL.stopPattern(3)) + .build(); + private static final Trip TRIP = TransitModelForTest.trip("trip1").build(); + private static final ScheduledTripTimes TRIP_TIMES = ScheduledTripTimes + .of() + .withArrivalTimes("10:00 11:00 12:00") + .withDepartureTimes("10:01 11:02 12:03") + .withTrip(TRIP) + .build(); @Test void defaultFares() { - var testModel = TransitModelForTest.of(); - var route = TransitModelForTest.route(id("2")).build(); - var pattern = TransitModelForTest - .tripPattern("1", route) - .withStopPattern(testModel.stopPattern(3)) + var leg = builder().build(); + + assertEquals(List.of(), leg.fareProducts()); + } + + @Test + void legTimesWithoutRealTime() { + var leg = builder().withTripTimes(TRIP_TIMES).build(); + + assertNull(leg.start().estimated()); + assertNull(leg.end().estimated()); + } + + @Test + void legTimesWithRealTime() { + var tt = ScheduledTripTimes + .of() + .withArrivalTimes("10:00 11:00 12:00") + .withDepartureTimes("10:01 11:02 12:03") + .withTrip(TRIP) .build(); - var leg = new ScheduledTransitLegBuilder() + + var rtt = RealTimeTripTimes.of(tt); + rtt.updateArrivalTime(0, 111); + + var leg = builder().withTripTimes(rtt).build(); + + assertNotNull(leg.start().estimated()); + assertNotNull(leg.end().estimated()); + } + + private static ScheduledTransitLegBuilder builder() { + return new ScheduledTransitLegBuilder() .withTripTimes(null) - .withTripPattern(pattern) + .withTripPattern(PATTERN) .withBoardStopIndexInPattern(0) .withAlightStopIndexInPattern(2) .withStartTime(TIME) .withEndTime(TIME.plusMinutes(10)) .withServiceDate(TIME.toLocalDate()) .withZoneId(ZoneIds.BERLIN) - .withGeneralizedCost(100) - .build(); - - assertEquals(List.of(), leg.fareProducts()); + .withGeneralizedCost(100); } } From 54c21a54a859bc2d692b439932fa67b095cc0137 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 09:04:43 +0100 Subject: [PATCH 36/83] Fix flex leg and spelling --- .../org/opentripplanner/ext/flex/FlexibleTransitLeg.java | 4 ++-- src/main/java/org/opentripplanner/model/plan/LegTime.java | 6 +++--- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index e0bdb6cc899..fac1118556f 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -87,12 +87,12 @@ public Accessibility getTripWheelchairAccessibility() { @Override public LegTime start() { - return LegTime.of(startTime, getArrivalDelay()); + return LegTime.ofStatic(startTime); } @Override public LegTime end() { - return LegTime.of(endTime, getDepartureDelay()); + return LegTime.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index 2dc97b92a11..4b30526ae82 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -9,14 +9,14 @@ /** * A scheduled time of a transit vehicle at a certain location with a optional realtime information. */ -public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealtimeEstimate estimated) { +public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated) { public LegTime { Objects.requireNonNull(scheduledTime); } @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTime(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); + return new LegTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); } @Nonnull public static LegTime ofStatic(ZonedDateTime staticTime) { @@ -39,5 +39,5 @@ public ZonedDateTime time() { * Realtime information about a vehicle at a certain place. * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. */ - record RealtimeEstimate(ZonedDateTime time, Duration delay) {} + record RealTimeEstimate(ZonedDateTime time, Duration delay) {} } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 93de5101451..29fcdf42a41 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1656,7 +1656,7 @@ ISO-8601 allows many different formats but OTP will only return the profile spec scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") "Real-time estimates for a vehicle at a certain place." -type RealtimeEstimate { +type RealTimeEstimate { time: OffsetDateTime! """ The delay or "earliness" of the vehicle at a certain place. @@ -1674,7 +1674,7 @@ type LegTime { "The scheduled time of the event." scheduledTime: OffsetDateTime! "The estimated time of the event. If no real-time information is available, this is null," - estimated: RealtimeEstimate + estimated: RealTimeEstimate } type Leg { From fb6005697deab6c5643fc81a49db4ea51d248066 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 23 Feb 2024 08:27:56 +0100 Subject: [PATCH 37/83] Remove invisible characters when parsing feed ids --- .../framework/lang/StringUtils.java | 21 ++++++++++++++++ .../transit/model/framework/FeedScopedId.java | 9 +++++-- .../framework/lang/StringUtilsTest.java | 7 ++++++ .../model/framework/FeedScopedIdTest.java | 24 +++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java index cbb32b9eaca..b231f980286 100644 --- a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java +++ b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java @@ -1,5 +1,6 @@ package org.opentripplanner.framework.lang; +import java.util.regex.Pattern; import javax.annotation.Nonnull; /** @@ -7,6 +8,15 @@ */ public class StringUtils { + /** + * Regex to find unprintable characters like newlines and 'ZERO WIDTH SPACE' (U+200B). + */ + private static final String INVISIBLE_CHARS_REGEX = "\\p{C}"; + /** + * Patterns are immutable and thread safe. + */ + private static final Pattern INVISIBLE_CHARS_PATTERN = Pattern.compile(INVISIBLE_CHARS_REGEX); + private StringUtils() {} /** true if the given text is not {@code null} or has at least one none white-space character. */ @@ -119,4 +129,15 @@ public static String quoteReplace(@Nonnull String text) { public static String kebabCase(String input) { return input.toLowerCase().replace('_', '-'); } + + /** + * Removes unprintable control characters like newlines, tabs and invisible whitespace + * like 'ZERO WIDTH SPACE' (U+200B) that don't have an immediate visual representation. + *

+ * Note that "regular" whitespace characters like U+0020 and U+2000 are considered visible and + * therefore not removed. + */ + public static String removeInvisibleChars(String input) { + return INVISIBLE_CHARS_PATTERN.matcher(input).replaceAll(""); + } } diff --git a/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java b/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java index d67ccc3d0e1..a0d7c72b751 100644 --- a/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java +++ b/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java @@ -5,9 +5,9 @@ import java.io.Serializable; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.opentripplanner.framework.lang.StringUtils; public final class FeedScopedId implements Serializable, Comparable { @@ -59,7 +59,12 @@ public static FeedScopedId parse(String value) throws IllegalArgumentException { * Parses a string consisting of concatenated FeedScopedIds to a List */ public static List parseList(String s) { - return Arrays.stream(s.split(",")).map(FeedScopedId::parse).collect(Collectors.toList()); + return Arrays + .stream(s.split(",")) + .map(input -> StringUtils.removeInvisibleChars(input).strip()) + .filter(i -> !i.isBlank()) + .map(FeedScopedId::parse) + .toList(); } public static boolean isValidString(String value) throws IllegalArgumentException { diff --git a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java index 8998d82a5f2..f65e5da4406 100644 --- a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java @@ -10,6 +10,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.ValueSource; import org.opentripplanner.test.support.VariableSource; class StringUtilsTest { @@ -82,4 +83,10 @@ void padRight() { void quoteReplace() { assertEquals("\"key\" : \"value\"", StringUtils.quoteReplace("'key' : 'value'")); } + + @ParameterizedTest + @ValueSource(strings = { "\u200B", "\n", "\t" }) + void removeInvisibleChars(String input) { + assertEquals("", StringUtils.removeInvisibleChars(input)); + } } diff --git a/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java b/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java index 08df670ed62..812c4c87fbf 100644 --- a/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java +++ b/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java @@ -3,13 +3,37 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class FeedScopedIdTest { + private static final List TRIMET_123 = List.of(new FeedScopedId("trimet", "123")); + @Test void ofNullable() { assertEquals(new FeedScopedId("FEED", "ID"), FeedScopedId.ofNullable("FEED", "ID")); assertNull(FeedScopedId.ofNullable("FEED", null)); } + + @ParameterizedTest + @ValueSource( + strings = { + "trimet:123", + "trimet:123 ", + "trimet:123, ", + ",trimet:123 , ", + ",trimet:123 , ,\u200B,", + " trimet:123 ", + "\u200Btrimet:123", + "\u200B\u200Btri\u200Bmet:123\u200B", + "\ntrimet:123\t", + "\ntri\nmet:123\t", + } + ) + void parseList(String input) { + assertEquals(TRIMET_123, FeedScopedId.parseList(input)); + } } From d99373db26b946b6c93fbc7ac875c6ba2eb52250 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 27 Feb 2024 11:40:38 +0100 Subject: [PATCH 38/83] Apply suggestions from code review Co-authored-by: Joel Lappalainen --- src/main/java/org/opentripplanner/model/plan/Leg.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 0063ecf87c2..c70c03112d6 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -206,7 +206,7 @@ default Accessibility getTripWheelchairAccessibility() { LegTime start(); /** - * The time (including realtime information) when the leg ends.. + * The time (including realtime information) when the leg ends. */ LegTime end(); From 47d28f1c8380efddad0871e58798313434b36f77 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 27 Feb 2024 11:41:52 +0100 Subject: [PATCH 39/83] Update deprecation notices --- .../org/opentripplanner/apis/gtfs/schema.graphqls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 29fcdf42a41..20f1f39af27 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1853,26 +1853,26 @@ type Leg { """ The date and time when this leg begins. Format: Unix timestamp in milliseconds. """ - startTime: Long @deprecated(reason: "Use `start.actual` instead which contains timezone information.") + startTime: Long @deprecated(reason: "Use `start.estimated.time` instead which contains timezone information.") """ The date and time when this leg ends. Format: Unix timestamp in milliseconds. """ - endTime: Long @deprecated(reason: "Use `end.actual` instead which contains timezone information.") + endTime: Long @deprecated(reason: "Use `end.estimated.time` instead which contains timezone information.") """ For transit leg, the offset from the scheduled departure time of the boarding stop in this leg, i.e. scheduled time of departure at boarding stop = `startTime - departureDelay` """ - departureDelay: Int @deprecated(reason: "Use `end.delay` instead.") + departureDelay: Int @deprecated(reason: "Use `end.estimated.delay` instead.") """ For transit leg, the offset from the scheduled arrival time of the alighting stop in this leg, i.e. scheduled time of arrival at alighting stop = `endTime - arrivalDelay` """ - arrivalDelay: Int @deprecated(reason: "Use `start.delay` instead.") + arrivalDelay: Int @deprecated(reason: "Use `start.estimated.delay` instead.") } From 337b10012d1a05cb3b86f6974c56c856b248aa11 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 27 Feb 2024 11:49:24 +0100 Subject: [PATCH 40/83] Add newline --- src/main/java/org/opentripplanner/model/plan/LegTime.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index 4b30526ae82..354ce4f4b0b 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -13,11 +13,13 @@ public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealTimeEs public LegTime { Objects.requireNonNull(scheduledTime); } + @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); return new LegTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); } + @Nonnull public static LegTime ofStatic(ZonedDateTime staticTime) { return new LegTime(staticTime, null); From 340ca13b7d2a132d3875c4da475855727b970b01 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 27 Feb 2024 12:28:55 +0100 Subject: [PATCH 41/83] Update documentation --- .../framework/lang/StringUtils.java | 7 ++++-- .../transit/model/framework/FeedScopedId.java | 7 +++++- .../framework/lang/StringUtilsTest.java | 15 +++++++++--- .../model/framework/FeedScopedIdTest.java | 23 +++++++++++++------ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java index b231f980286..1e57fb55027 100644 --- a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java +++ b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java @@ -10,6 +10,9 @@ public class StringUtils { /** * Regex to find unprintable characters like newlines and 'ZERO WIDTH SPACE' (U+200B). + *

+ * \p{C} was chosen over \p{Cntrl} because it also recognises invisible control characters in the + * middle of a word. */ private static final String INVISIBLE_CHARS_REGEX = "\\p{C}"; /** @@ -137,7 +140,7 @@ public static String kebabCase(String input) { * Note that "regular" whitespace characters like U+0020 and U+2000 are considered visible and * therefore not removed. */ - public static String removeInvisibleChars(String input) { - return INVISIBLE_CHARS_PATTERN.matcher(input).replaceAll(""); + public static boolean containsInvisibleCharacters(String input) { + return INVISIBLE_CHARS_PATTERN.matcher(input).find(); } } diff --git a/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java b/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java index a0d7c72b751..b48ff040c28 100644 --- a/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java +++ b/src/main/java/org/opentripplanner/transit/model/framework/FeedScopedId.java @@ -59,9 +59,14 @@ public static FeedScopedId parse(String value) throws IllegalArgumentException { * Parses a string consisting of concatenated FeedScopedIds to a List */ public static List parseList(String s) { + if (StringUtils.containsInvisibleCharacters(s)) { + throw new IllegalArgumentException( + "The input string '%s' contains invisible characters which is not allowed.".formatted(s) + ); + } return Arrays .stream(s.split(",")) - .map(input -> StringUtils.removeInvisibleChars(input).strip()) + .map(String::strip) .filter(i -> !i.isBlank()) .map(FeedScopedId::parse) .toList(); diff --git a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java index f65e5da4406..c9a0df963e0 100644 --- a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java @@ -3,6 +3,7 @@ import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -85,8 +86,16 @@ void quoteReplace() { } @ParameterizedTest - @ValueSource(strings = { "\u200B", "\n", "\t" }) - void removeInvisibleChars(String input) { - assertEquals("", StringUtils.removeInvisibleChars(input)); + @ValueSource( + strings = { "\u200B", "\n", "\t", "\thello", "f\noo", "\ntri\nmet:123\t", "tri\u200Bmet:123" } + ) + void containsInvisibleChars(String input) { + assertTrue(StringUtils.containsInvisibleCharacters(input)); + } + + @ParameterizedTest + @ValueSource(strings = { "", " ", "hello", " hello", " fo o " }) + void noInvisibleChars(String input) { + assertFalse(StringUtils.containsInvisibleCharacters(input)); } } diff --git a/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java b/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java index 812c4c87fbf..a7c7c5ff058 100644 --- a/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java +++ b/src/test/java/org/opentripplanner/transit/model/framework/FeedScopedIdTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import java.util.List; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -18,22 +19,30 @@ void ofNullable() { assertNull(FeedScopedId.ofNullable("FEED", null)); } + @ParameterizedTest + @ValueSource( + strings = { "trimet:123", "trimet:123 ", "trimet:123, ", ",trimet:123 , ", " trimet:123 " } + ) + void parseList(String input) { + assertEquals(TRIMET_123, FeedScopedId.parseList(input)); + } + @ParameterizedTest @ValueSource( strings = { - "trimet:123", - "trimet:123 ", - "trimet:123, ", - ",trimet:123 , ", ",trimet:123 , ,\u200B,", - " trimet:123 ", "\u200Btrimet:123", "\u200B\u200Btri\u200Bmet:123\u200B", "\ntrimet:123\t", "\ntri\nmet:123\t", } ) - void parseList(String input) { - assertEquals(TRIMET_123, FeedScopedId.parseList(input)); + void throwExceptionForInvisibleChar(String input) { + Assertions.assertThrows( + IllegalArgumentException.class, + () -> { + FeedScopedId.parseList(input); + } + ); } } From a6f1b88fcf9f5b4dfec821973758d0cb45b5d374 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 29 Feb 2024 17:30:23 +0100 Subject: [PATCH 42/83] Prevent feed id from being used twice --- .../gtfs/graphbuilder/GtfsModule.java | 36 ++++++++++++++++++- .../graph_builder/module/GtfsModuleTest.java | 33 ++++++++++++----- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java b/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java index cf9d48c64c5..2f7feb5993e 100644 --- a/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java +++ b/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java @@ -120,12 +120,20 @@ public void buildGraph() { boolean hasTransit = false; + Map feedIdsEncountered = new HashMap<>(); + try { for (GtfsBundle gtfsBundle : gtfsBundles) { GtfsMutableRelationalDao gtfsDao = loadBundle(gtfsBundle); + + final String feedId = gtfsBundle.getFeedId().getId(); + verifyUniqueFeedId(gtfsBundle, feedIdsEncountered, feedId); + + feedIdsEncountered.put(feedId, gtfsBundle); + GTFSToOtpTransitServiceMapper mapper = new GTFSToOtpTransitServiceMapper( new OtpTransitServiceBuilder(transitModel.getStopModel(), issueStore), - gtfsBundle.getFeedId().getId(), + feedId, issueStore, gtfsBundle.discardMinTransferTimes(), gtfsDao, @@ -203,6 +211,32 @@ public void buildGraph() { transitModel.updateCalendarServiceData(hasTransit, calendarServiceData, issueStore); } + /** + * Verifies that a feed id is not assigned twice. + *

+ * Duplicates can happen in the following cases: + * - the feed id is configured twice in build-config.json + * - two GTFS feeds have the same feed_info.feed_id + * - a GTFS feed defines a feed_info.feed_id like '3' that collides with an auto-generated one + *

+ * Debugging these cases is very confusing, so we prevent it from happening. + */ + private static void verifyUniqueFeedId( + GtfsBundle gtfsBundle, + Map feedIdsEncountered, + String feedId + ) { + if (feedIdsEncountered.containsKey(feedId)) { + LOG.error( + "Feed id '{}' has been used for {} but it was already assigned to {}.", + feedId, + gtfsBundle, + feedIdsEncountered.get(feedId) + ); + throw new IllegalArgumentException("Duplicate feed id: '%s'".formatted(feedId)); + } + } + @Override public void checkInputs() { for (GtfsBundle bundle : gtfsBundles) { diff --git a/src/test/java/org/opentripplanner/graph_builder/module/GtfsModuleTest.java b/src/test/java/org/opentripplanner/graph_builder/module/GtfsModuleTest.java index c628a14ad43..8123661990e 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/GtfsModuleTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/GtfsModuleTest.java @@ -2,6 +2,7 @@ import static graphql.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.List; import java.util.stream.Collectors; @@ -23,7 +24,7 @@ class GtfsModuleTest { @Test - public void addShapesForFrequencyTrips() { + void addShapesForFrequencyTrips() { var model = buildTestModel(); var bundle = new GtfsBundle(ConstantsForTests.SIMPLE_GTFS); @@ -44,7 +45,7 @@ public void addShapesForFrequencyTrips() { assertEquals(1, frequencyTripPattern.size()); - var tripPattern = frequencyTripPattern.get(0); + var tripPattern = frequencyTripPattern.getFirst(); assertNotNull(tripPattern.getGeometry()); assertNotNull(tripPattern.getHopGeometry(0)); @@ -53,6 +54,20 @@ public void addShapesForFrequencyTrips() { assertNotNull(pattern.getHopGeometry(0)); } + @Test + void duplicateFeedId() { + var bundles = List.of(bundle("A"), bundle("A")); + var model = buildTestModel(); + + var module = new GtfsModule( + bundles, + model.transitModel, + model.graph, + ServiceDateInterval.unbounded() + ); + assertThrows(IllegalArgumentException.class, module::buildGraph); + } + private static TestModels buildTestModel() { var deduplicator = new Deduplicator(); var stopModel = new StopModel(); @@ -63,15 +78,15 @@ private static TestModels buildTestModel() { record TestModels(Graph graph, TransitModel transitModel) {} + static GtfsBundle bundle(String feedId) { + var b = new GtfsBundle(ResourceLoader.of(GtfsModuleTest.class).file("/gtfs/interlining")); + b.setFeedId(new GtfsFeedId.Builder().id(feedId).build()); + return b; + } + @Nested class Interlining { - static GtfsBundle bundle(String feedId) { - var b = new GtfsBundle(ResourceLoader.of(GtfsModuleTest.class).file("/gtfs/interlining")); - b.setFeedId(new GtfsFeedId.Builder().id(feedId).build()); - return b; - } - static List interliningCases() { return List.of( Arguments.of(List.of(bundle("A")), 2), @@ -86,7 +101,7 @@ static List interliningCases() { */ @ParameterizedTest(name = "Bundles {0} should generate {1} stay-seated transfers") @MethodSource("interliningCases") - public void interline(List bundles, int expectedTransfers) { + void interline(List bundles, int expectedTransfers) { var model = buildTestModel(); var feedIds = bundles.stream().map(GtfsBundle::getFeedId).collect(Collectors.toSet()); From df0d65b61222bf971e2d3c6daf67fa13132b91ed Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 1 Mar 2024 14:22:55 +0100 Subject: [PATCH 43/83] Always put minus as the first sign of a serialized negative duration --- .../graphql/scalar/DurationScalarFactory.java | 2 +- .../framework/time/DurationUtils.java | 18 +++++++++++++ .../opentripplanner/apis/gtfs/schema.graphqls | 4 +-- .../apis/gtfs/GraphQLScalarsTest.java | 4 ++- .../framework/time/DurationUtilsTest.java | 27 +++++++++++++++++++ 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java b/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java index 30dd3754198..50af0fbc759 100644 --- a/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java +++ b/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java @@ -33,7 +33,7 @@ private static class DurationCoercing implements Coercing { @Nonnull public String serialize(@Nonnull Object input) throws CoercingSerializeException { if (input instanceof Duration duration) { - return duration.toString(); + return DurationUtils.formatDurationWithLeadingMinus(duration); } throw new CoercingSerializeException(input + " cannot be cast to 'Duration'"); diff --git a/src/main/java/org/opentripplanner/framework/time/DurationUtils.java b/src/main/java/org/opentripplanner/framework/time/DurationUtils.java index bf59964fbb2..9a01d308a1c 100644 --- a/src/main/java/org/opentripplanner/framework/time/DurationUtils.java +++ b/src/main/java/org/opentripplanner/framework/time/DurationUtils.java @@ -196,4 +196,22 @@ public static int toIntMilliseconds(Duration timeout, int defaultValue) { private static String msToSecondsStr(String formatSeconds, double timeMs) { return String.format(ROOT, formatSeconds, timeMs / 1000.0) + " seconds"; } + + /** + * Formats a duration and if it's a negative amount, it places the minus before the "P" rather + * than in the middle of the value. + *

+ * Background: There are multiple ways to express -1.5 hours: "PT-1H-30M" and "-PT1H30M". + *

+ * The first version is what you get when calling toString() but it's quite confusing. Therefore, + * this method makes sure that you get the second form "-PT1H30M". + */ + public static String formatDurationWithLeadingMinus(Duration duration) { + if (duration.isNegative()) { + var positive = duration.abs().toString(); + return "-" + positive; + } else { + return duration.toString(); + } + } } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 20f1f39af27..655a1908a87 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1625,9 +1625,9 @@ type Money { """" An ISO-8601-formatted duration, i.e. `PT2H30M` for 2 hours and 30 minutes. -Negative durations are formatted like `PT-10M`. +Negative durations are formatted like `-PT10M`. """ -scalar Duration +scalar Duration @specifiedBy(url:"https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/Duration.html#parse(java.lang.CharSequence)") type RideHailingProvider { "The ID of the ride hailing provider." diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 652c72254d9..5183279cec7 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -35,7 +35,9 @@ static List durationCases() { return List.of( of(Duration.ofMinutes(30), "PT30M"), of(Duration.ofHours(23), "PT23H"), - of(Duration.ofMinutes(-10), "PT-10M") + of(Duration.ofMinutes(-10), "-PT10M"), + of(Duration.ofMinutes(-90), "-PT1H30M"), + of(Duration.ofMinutes(-184), "-PT3H4M") ); } diff --git a/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java b/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java index 86953760485..2457aa14b60 100644 --- a/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.provider.Arguments.of; import static org.opentripplanner.framework.time.DurationUtils.requireNonNegative; import static org.opentripplanner.framework.time.DurationUtils.toIntMilliseconds; @@ -13,6 +14,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.ResourceLock; import org.junit.jupiter.api.parallel.Resources; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class DurationUtilsTest { @@ -151,6 +155,29 @@ public void msToSecondsStr() { } } + static List durationCases() { + return List.of( + of(Duration.ofSeconds(30), "PT30S"), + of(Duration.ofMinutes(30), "PT30M"), + of(Duration.ofHours(23), "PT23H"), + of(Duration.ofSeconds(-30), "-PT30S"), + of(Duration.ofMinutes(-10), "-PT10M"), + of(Duration.ofMinutes(-90), "-PT1H30M"), + of(Duration.ofMinutes(-184), "-PT3H4M") + ); + } + + @ParameterizedTest + @MethodSource("durationCases") + void formatDuration(Duration duration, String expected) { + var string = DurationUtils.formatDurationWithLeadingMinus(duration); + + assertEquals(expected, string); + + var parsed = Duration.parse(expected); + assertEquals(parsed, duration); + } + private static int durationSec(int hour, int min, int sec) { return 60 * (60 * hour + min) + sec; } From f723c25a421b00c58fb7b1e32ca29ee31583e41c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 21:22:17 +0100 Subject: [PATCH 44/83] Revert conversion to record --- .../flex/trip/ScheduledDeviatedTripTest.java | 2 +- .../ext/restapi/mapping/PlaceMapper.java | 10 ++-- .../apis/gtfs/datafetchers/LegImpl.java | 2 +- .../apis/gtfs/datafetchers/PlaceImpl.java | 58 ++++++++++++++----- .../apis/transmodel/model/plan/LegType.java | 2 +- .../org/opentripplanner/model/plan/Leg.java | 2 +- .../model/plan/StopArrival.java | 43 +++++++++----- .../algorithm/mapping/AlertToLegMapper.java | 6 +- 8 files changed, 83 insertions(+), 42 deletions(-) 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 546f8c411ac..143388cac0f 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 @@ -185,7 +185,7 @@ void flexTripInTransitMode() { var intermediateStops = leg.getIntermediateStops(); assertEquals(1, intermediateStops.size()); - assertEquals("zone_1", intermediateStops.get(0).place().stop.getId().getId()); + assertEquals("zone_1", intermediateStops.get(0).place.stop.getId().getId()); EncodedPolyline legGeometry = EncodedPolyline.encode(leg.getLegGeometry()); assertThatPolylinesAreEqual( diff --git a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java index 95669d4b7ca..28ceb0b84e3 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java @@ -38,11 +38,11 @@ public List mapStopArrivals(Collection domain) { public ApiPlace mapStopArrival(StopArrival domain) { return mapPlace( - domain.place(), - domain.arrival().time(), - domain.departure().time(), - domain.stopPosInPattern(), - domain.gtfsStopSequence() + domain.place, + domain.arrival.time(), + domain.departure.time(), + domain.stopPosInPattern, + domain.gtfsStopSequence ); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index f7be76481a7..975d8d56831 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -144,7 +144,7 @@ public DataFetcher> intermediateStops() { } return intermediateStops .stream() - .map(intermediateStop -> intermediateStop.place().stop) + .map(intermediateStop -> intermediateStop.place.stop) .filter(Objects::nonNull) .collect(Collectors.toList()); }; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 16716a393d1..9ce80bcaf7f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -20,13 +20,16 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override public DataFetcher arrival() { - return environment -> getSource(environment).arrival(); + return environment -> getSource(environment).arrival; } @Deprecated @Override public DataFetcher arrivalTime() { - return environment -> getSource(environment).arrival().time().toInstant().toEpochMilli(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.arrival.time().toInstant().toEpochMilli(); + }; } @Override @@ -37,7 +40,8 @@ public DataFetcher bikePark() { @Override public DataFetcher bikeRentalStation() { return environment -> { - Place place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + Place place = stopArrival.place; if (!place.vertexType.equals(VertexType.VEHICLERENTAL)) { return null; @@ -55,34 +59,47 @@ public DataFetcher carPark() { @Deprecated @Override public DataFetcher departure() { - return environment -> getSource(environment).departure(); + return environment -> getSource(environment).departure; } @Override public DataFetcher departureTime() { - return environment -> getSource(environment).departure().time().toInstant().toEpochMilli(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.departure.time().toInstant().toEpochMilli(); + }; } @Override public DataFetcher lat() { - return environment -> getSource(environment).place().coordinate.latitude(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.place.coordinate.latitude(); + }; } @Override public DataFetcher lon() { - return environment -> getSource(environment).place().coordinate.longitude(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.place.coordinate.longitude(); + }; } @Override public DataFetcher name() { return environment -> - GraphQLUtils.getTranslation(getSource(environment).place().name, environment); + { + StopArrival stopArrival = getSource(environment); + return GraphQLUtils.getTranslation(stopArrival.place.name, environment); + }; } @Override public DataFetcher rentalVehicle() { return environment -> { - Place place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + Place place = stopArrival.place; if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -97,13 +114,17 @@ public DataFetcher rentalVehicle() { @Override public DataFetcher stop() { - return environment -> getSource(environment).place().stop; + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.place.stop; + }; } @Override public DataFetcher stopPosition() { return environment -> { - var seq = getSource(environment).gtfsStopSequence(); + StopArrival stopArrival = getSource(environment); + var seq = stopArrival.gtfsStopSequence; if (seq != null) { return new PositionAtStop(seq); } else { @@ -120,7 +141,8 @@ public DataFetcher vehicleParking() { @Override public DataFetcher vehicleRentalStation() { return environment -> { - Place place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + Place place = stopArrival.place; if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -136,7 +158,8 @@ public DataFetcher vehicleRentalStation() { @Override public DataFetcher vertexType() { return environment -> { - var place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + var place = stopArrival.place; return switch (place.vertexType) { case NORMAL -> GraphQLVertexType.NORMAL.name(); case TRANSIT -> GraphQLVertexType.TRANSIT.name(); @@ -147,7 +170,8 @@ public DataFetcher vertexType() { } private VehicleParking getBikePark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; + StopArrival stopArrival = getSource(environment); + var vehicleParkingWithEntrance = stopArrival.place.vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasBicyclePlaces() @@ -159,7 +183,8 @@ private VehicleParking getBikePark(DataFetchingEnvironment environment) { } private VehicleParking getCarPark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; + StopArrival stopArrival = getSource(environment); + var vehicleParkingWithEntrance = stopArrival.place.vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasAnyCarPlaces() @@ -171,7 +196,8 @@ private VehicleParking getCarPark(DataFetchingEnvironment environment) { } private VehicleParking getVehicleParking(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; + StopArrival stopArrival = getSource(environment); + var vehicleParkingWithEntrance = stopArrival.place.vehicleParkingWithEntrance; if (vehicleParkingWithEntrance == null) { return null; } diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java index 99ead9fd8c0..be05d00e16d 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java @@ -340,7 +340,7 @@ public static GraphQLObjectType create( return ( stops .stream() - .map(stop -> stop.place().stop) + .map(stop -> stop.place.stop) .filter(Objects::nonNull) .collect(Collectors.toList()) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index c70c03112d6..5a032def979 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -462,7 +462,7 @@ default Leg withTimeShift(Duration duration) { default Set getFareZones() { var intermediate = getIntermediateStops() .stream() - .flatMap(stopArrival -> stopArrival.place().stop.getFareZones().stream()); + .flatMap(stopArrival -> stopArrival.place.stop.getFareZones().stream()); var start = getFareZones(this.getFrom()); var end = getFareZones(this.getTo()); diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 8a6b55c9346..8435013cfb5 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -5,21 +5,36 @@ /** * This class is used to represent a stop arrival event mostly for intermediate visits to a stops * along a route. - * - * @param arrival The time the rider will arrive at the place. - * @param departure The time the rider will depart the place. - * @param stopPosInPattern For transit trips, the stop index (numbered from zero from the start of - * the trip). - * @param gtfsStopSequence For transit trips, the sequence number of the stop. Per GTFS, these - * numbers are increasing. */ -public record StopArrival( - Place place, - LegTime arrival, - LegTime departure, - Integer stopPosInPattern, - Integer gtfsStopSequence -) { +public final class StopArrival { + public final Place place; + public final LegTime arrival; + public final LegTime departure; + public final Integer stopPosInPattern; + public final Integer gtfsStopSequence; + + /** + * @param arrival The time the rider will arrive at the place. + * @param departure The time the rider will depart the place. + * @param stopPosInPattern For transit trips, the stop index (numbered from zero from the start of + * the trip). + * @param gtfsStopSequence For transit trips, the sequence number of the stop. Per GTFS, these + * numbers are increasing. + */ + public StopArrival( + Place place, + LegTime arrival, + LegTime departure, + Integer stopPosInPattern, + Integer gtfsStopSequence + ) { + this.place = place; + this.arrival = arrival; + this.departure = departure; + this.stopPosInPattern = stopPosInPattern; + this.gtfsStopSequence = gtfsStopSequence; + } + @Override public String toString() { return ToStringBuilder diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java index 4b2b194fbe4..94630be7600 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java @@ -81,7 +81,7 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { if (leg.getIntermediateStops() != null) { Set stopConditions = StopCondition.PASSING; for (StopArrival visit : leg.getIntermediateStops()) { - if (visit.place().stop instanceof RegularStop stop) { + if (visit.place.stop instanceof RegularStop stop) { Collection alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions); alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions)); alerts.addAll( @@ -91,8 +91,8 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { ) ); - ZonedDateTime stopArrival = visit.arrival().scheduledTime(); - ZonedDateTime stopDeparture = visit.departure().scheduledTime(); + ZonedDateTime stopArrival = visit.arrival.scheduledTime(); + ZonedDateTime stopDeparture = visit.departure.scheduledTime(); addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture); } From 91989e297ee37707302f09ede6b7ab4c18032c78 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 21:32:41 +0100 Subject: [PATCH 45/83] Extract mapper for StopArrivals --- .../apis/gtfs/datafetchers/PlaceImpl.java | 3 +- .../model/plan/ScheduledTransitLeg.java | 29 +---------- .../model/plan/StopArrival.java | 1 + .../model/plan/StopArrivalMapper.java | 52 +++++++++++++++++++ 4 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 9ce80bcaf7f..145321f809c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -88,8 +88,7 @@ public DataFetcher lon() { @Override public DataFetcher name() { - return environment -> - { + return environment -> { StopArrival stopArrival = getSource(environment); return GraphQLUtils.getTranslation(stopArrival.place.name, environment); }; diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index a4050fc3cb2..6bf39d5aa4c 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -275,36 +275,11 @@ public Place getTo() { @Override public List getIntermediateStops() { List visits = new ArrayList<>(); + var mapper = new StopArrivalMapper(zoneId, serviceDate, tripTimes); for (int i = boardStopPosInPattern + 1; i < alightStopPosInPattern; i++) { StopLocation stop = tripPattern.getStop(i); - - final var arrivalTime = ServiceDateUtils.toZonedDateTime( - serviceDate, - zoneId, - tripTimes.getArrivalTime(i) - ); - final var departureTime = ServiceDateUtils.toZonedDateTime( - serviceDate, - zoneId, - tripTimes.getDepartureTime(i) - ); - - var arrival = LegTime.ofStatic(arrivalTime); - var departure = LegTime.ofStatic(departureTime); - - if (getRealTime()) { - arrival = LegTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = LegTime.of(departureTime, tripTimes.getDepartureDelay(i)); - } - - StopArrival visit = new StopArrival( - Place.forStop(stop), - arrival, - departure, - i, - tripTimes.gtfsSequenceOfStopIndex(i) - ); + final StopArrival visit = mapper.map(i, stop, getRealTime()); visits.add(visit); } return visits; diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 8435013cfb5..489b122da09 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -7,6 +7,7 @@ * along a route. */ public final class StopArrival { + public final Place place; public final LegTime arrival; public final LegTime departure; diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java new file mode 100644 index 00000000000..3a907e8cffb --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -0,0 +1,52 @@ +package org.opentripplanner.model.plan; + +import java.time.LocalDate; +import java.time.ZoneId; +import org.opentripplanner.framework.time.ServiceDateUtils; +import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.TripTimes; + +/** + * Maps leg-related information to an instance of {@link StopArrival}. + */ +class StopArrivalMapper { + + private final ZoneId zoneId; + private final LocalDate serviceDate; + private final TripTimes tripTimes; + + public StopArrivalMapper(ZoneId zoneId, LocalDate serviceDate, TripTimes tripTimes) { + this.zoneId = zoneId; + this.serviceDate = serviceDate; + this.tripTimes = tripTimes; + } + + StopArrival map(int i, StopLocation stop, boolean realTime) { + final var arrivalTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getArrivalTime(i) + ); + final var departureTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getDepartureTime(i) + ); + + var arrival = LegTime.ofStatic(arrivalTime); + var departure = LegTime.ofStatic(departureTime); + + if (realTime) { + arrival = LegTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTime.of(departureTime, tripTimes.getDepartureDelay(i)); + } + + return new StopArrival( + Place.forStop(stop), + arrival, + departure, + i, + tripTimes.gtfsSequenceOfStopIndex(i) + ); + } +} From 84083b6476ad1afd52d48405e024838751ecfef9 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 21:36:29 +0100 Subject: [PATCH 46/83] Separate tests several classes --- .../apis/gtfs/DurationScalarTest.java | 41 ++++++ .../apis/gtfs/GeoJsonScalarTest.java | 31 +++++ .../apis/gtfs/GraphQLScalarsTest.java | 119 ------------------ .../apis/gtfs/OffsetDateTimeScalarTest.java | 62 +++++++++ 4 files changed, 134 insertions(+), 119 deletions(-) create mode 100644 src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java create mode 100644 src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java delete mode 100644 src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java create mode 100644 src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java diff --git a/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java new file mode 100644 index 00000000000..ca87311ac3a --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java @@ -0,0 +1,41 @@ +package org.opentripplanner.apis.gtfs; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.of; + +import graphql.schema.CoercingSerializeException; +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.Assertions; +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; + +public class DurationScalarTest { + + static List durationCases() { + return List.of( + of(Duration.ofMinutes(30), "PT30M"), + of(Duration.ofHours(23), "PT23H"), + of(Duration.ofMinutes(-10), "-PT10M"), + of(Duration.ofMinutes(-90), "-PT1H30M"), + of(Duration.ofMinutes(-184), "-PT3H4M") + ); + } + + @ParameterizedTest + @MethodSource("durationCases") + void duration(Duration duration, String expected) { + var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); + assertEquals(expected, string); + } + + @Test + void nonDuration() { + Assertions.assertThrows( + CoercingSerializeException.class, + () -> GraphQLScalars.durationScalar.getCoercing().serialize(new Object()) + ); + } +} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java new file mode 100644 index 00000000000..92188e603c4 --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java @@ -0,0 +1,31 @@ +package org.opentripplanner.apis.gtfs; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.opentripplanner.framework.json.ObjectMappers; + +class GeoJsonScalarTest { + + @Test + void geoJson() throws JsonProcessingException { + var gm = new GeometryFactory(); + var polygon = gm.createPolygon( + new Coordinate[] { + new Coordinate(0, 0), + new Coordinate(1, 1), + new Coordinate(2, 2), + new Coordinate(0, 0), + } + ); + var geoJson = GraphQLScalars.geoJsonScalar.getCoercing().serialize(polygon); + + var jsonNode = ObjectMappers + .ignoringExtraFields() + .readTree("{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[1,1],[2,2],[0,0]]]}"); + assertEquals(jsonNode.toString(), geoJson.toString()); + } +} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java deleted file mode 100644 index 5183279cec7..00000000000 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.opentripplanner.apis.gtfs; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.params.provider.Arguments.of; - -import com.fasterxml.jackson.core.JsonProcessingException; -import graphql.language.StringValue; -import graphql.schema.CoercingSerializeException; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Nested; -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.GeometryFactory; -import org.opentripplanner._support.time.ZoneIds; -import org.opentripplanner.framework.json.ObjectMappers; - -class GraphQLScalarsTest { - - static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( - LocalDate.of(2024, 2, 4), - LocalTime.MIDNIGHT, - ZoneOffset.UTC - ); - - static List durationCases() { - return List.of( - of(Duration.ofMinutes(30), "PT30M"), - of(Duration.ofHours(23), "PT23H"), - of(Duration.ofMinutes(-10), "-PT10M"), - of(Duration.ofMinutes(-90), "-PT1H30M"), - of(Duration.ofMinutes(-184), "-PT3H4M") - ); - } - - @ParameterizedTest - @MethodSource("durationCases") - void duration(Duration duration, String expected) { - var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); - assertEquals(expected, string); - } - - @Test - void nonDuration() { - Assertions.assertThrows( - CoercingSerializeException.class, - () -> GraphQLScalars.durationScalar.getCoercing().serialize(new Object()) - ); - } - - @Test - void geoJson() throws JsonProcessingException { - var gm = new GeometryFactory(); - var polygon = gm.createPolygon( - new Coordinate[] { - new Coordinate(0, 0), - new Coordinate(1, 1), - new Coordinate(2, 2), - new Coordinate(0, 0), - } - ); - var geoJson = GraphQLScalars.geoJsonScalar.getCoercing().serialize(polygon); - - var jsonNode = ObjectMappers - .ignoringExtraFields() - .readTree("{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[1,1],[2,2],[0,0]]]}"); - assertEquals(jsonNode.toString(), geoJson.toString()); - } - - @Nested - class OffsetDateTimeTests { - - static List offsetDateTimeCases() { - return List.of( - of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), - of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), - "2024-02-04T01:00:00+01:00" - ), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), - "2024-02-03T19:00:00-05:00" - ) - ); - } - - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void serializeOffsetDateTime(OffsetDateTime odt, String expected) { - var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); - assertEquals(expected, string); - } - - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void parseOffsetDateTime(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); - assertEquals(expected, odt); - } - - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar - .getCoercing() - .parseLiteral(new StringValue(input)); - assertEquals(expected, odt); - } - } -} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java new file mode 100644 index 00000000000..890bf1eeed1 --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java @@ -0,0 +1,62 @@ +package org.opentripplanner.apis.gtfs; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.of; + +import graphql.language.StringValue; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.List; +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; + +public class OffsetDateTimeScalarTest { + + static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( + LocalDate.of(2024, 2, 4), + LocalTime.MIDNIGHT, + ZoneOffset.UTC + ); + + static List offsetDateTimeCases() { + return List.of( + of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), + of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), + "2024-02-04T01:00:00+01:00" + ), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), + "2024-02-03T19:00:00-05:00" + ) + ); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void serializeOffsetDateTime(OffsetDateTime odt, String expected) { + var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + assertEquals(expected, string); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTime(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); + assertEquals(expected, odt); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar + .getCoercing() + .parseLiteral(new StringValue(input)); + assertEquals(expected, odt); + } +} From 10fac09bdd9c3481256fd8be7f5682b1dc12ab04 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 22:32:33 +0100 Subject: [PATCH 47/83] Make parser return throw an exception --- .../apis/gtfs/GraphQLScalars.java | 31 ++++++++++++------- .../framework/time/OffsetDateTimeParser.java | 10 +++--- .../time/OffsetDateTimeParserTest.java | 14 ++++++--- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 7d70f4be3b5..f0e4f295055 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -10,6 +10,7 @@ import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; +import java.text.ParseException; import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -79,26 +80,34 @@ public String serialize(@Nonnull Object dataFetcherResult) @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { if (input instanceof CharSequence cs) { - return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); + try { + return OffsetDateTimeParser.parseLeniently(cs); + } catch (ParseException e) { + int errorOffset = e.getErrorOffset(); + throw new CoercingParseValueException( + "Cannot parse %s into an OffsetDateTime. Error at character index %s".formatted( + input, + errorOffset + ) + ); + } } - throw valueException(input); + throw new CoercingParseValueException( + "Cannot parse %s into an OffsetDateTime. Must be a string." + ); } @Override public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { if (input instanceof StringValue sv) { - return OffsetDateTimeParser - .parseLeniently(sv.getValue()) - .orElseThrow(CoercingParseLiteralException::new); + try { + return OffsetDateTimeParser.parseLeniently(sv.getValue()); + } catch (ParseException e) { + throw new CoercingSerializeException(); + } } throw new CoercingParseLiteralException(); } - - private static CoercingParseValueException valueException(Object input) { - return new CoercingParseValueException( - "Cannot parse %s into an OffsetDateTime.".formatted(input) - ); - } } ) .build(); diff --git a/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java index 11652d797a7..8b40697977a 100644 --- a/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java +++ b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java @@ -1,10 +1,10 @@ package org.opentripplanner.framework.time; +import java.text.ParseException; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; -import java.util.Optional; public class OffsetDateTimeParser { @@ -30,13 +30,13 @@ public class OffsetDateTimeParser { /** * Parses a ISO-8601 string into am OffsetDateTime instance allowing the offset to be both in * '02:00' and '0200' format. + * @throws ParseException if the string cannot be parsed */ - public static Optional parseLeniently(CharSequence input) { + public static OffsetDateTime parseLeniently(CharSequence input) throws ParseException { try { - var result = OffsetDateTime.parse(input, LENIENT_PARSER); - return Optional.of(result); + return OffsetDateTime.parse(input, LENIENT_PARSER); } catch (DateTimeParseException e) { - return Optional.empty(); + throw new ParseException(e.getParsedString(), e.getErrorIndex()); } } } diff --git a/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java index 1f164ada783..d8944b9a5f0 100644 --- a/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java +++ b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java @@ -2,8 +2,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; +import java.text.ParseException; import java.time.OffsetDateTime; import java.util.List; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -27,9 +29,9 @@ static List successfulCases() { @ParameterizedTest @MethodSource("successfulCases") - void parse(String input) { + void parse(String input) throws ParseException { var res = OffsetDateTimeParser.parseLeniently(input); - assertTrue(res.get().isEqual(TIME)); + assertTrue(res.isEqual(TIME)); } static List failedCases() { @@ -39,7 +41,11 @@ static List failedCases() { @ParameterizedTest @MethodSource("failedCases") void failed(String input) { - var res = OffsetDateTimeParser.parseLeniently(input); - assertTrue(res.isEmpty()); + Assertions.assertThrows( + ParseException.class, + () -> { + OffsetDateTimeParser.parseLeniently(input); + } + ); } } From 009eb99f6b8796702ac5112983dbfd4f3dd28a59 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 10:02:44 +0100 Subject: [PATCH 48/83] Remove arrival/departure in example --- docs/apis/GraphQL-Tutorial.md | 14 ------ .../apis/gtfs/expectations/plan.json | 44 ------------------- .../apis/gtfs/queries/plan.graphql | 14 ------ 3 files changed, 72 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 7e1f6b0f6db..92645f9b245 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -96,13 +96,6 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - arrival { - scheduledTime - estimated { - time - delay - } - } departure { scheduledTime estimated { @@ -122,13 +115,6 @@ Most people want to get routing results out of OTP, so lets see the query for th delay } } - departure { - scheduledTime - estimated { - time - delay - } - } } route { gtfsId diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index ec971af5b3c..d213443f7cd 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -12,10 +12,6 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "arrival" : { - "scheduledTime" : "2020-02-02T11:00:00Z", - "estimated" : null - }, "departure" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null @@ -28,10 +24,6 @@ "arrival" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null - }, - "departure" : { - "scheduledTime" : "2020-02-02T11:00:20Z", - "estimated" : null } }, "route" : null, @@ -43,13 +35,6 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "arrival" : { - "scheduledTime" : "2020-02-02T10:51:00Z", - "estimated" : { - "time" : "2020-02-02T11:01:00Z", - "delay" : "PT10M" - } - }, "departure" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { @@ -68,13 +53,6 @@ "time" : "2020-02-02T11:15:00Z", "delay" : "PT10M" } - }, - "departure" : { - "scheduledTime" : "2020-02-02T11:05:00Z", - "estimated" : { - "time" : "2020-02-02T11:15:00Z", - "delay" : "PT10M" - } } }, "route" : { @@ -92,13 +70,6 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "arrival" : { - "scheduledTime" : "2020-02-02T11:20:00Z", - "estimated" : { - "time" : "2020-02-02T11:30:00Z", - "delay" : "PT10M" - } - }, "departure" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { @@ -117,13 +88,6 @@ "time" : "2020-02-02T11:50:00Z", "delay" : "PT10M" } - }, - "departure" : { - "scheduledTime" : "2020-02-02T11:40:00Z", - "estimated" : { - "time" : "2020-02-02T11:50:00Z", - "delay" : "PT10M" - } } }, "route" : { @@ -141,10 +105,6 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "arrival" : { - "scheduledTime" : "2020-02-02T11:50:00Z", - "estimated" : null - }, "departure" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null @@ -157,10 +117,6 @@ "arrival" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null - }, - "departure" : { - "scheduledTime" : "2020-02-02T12:00:00Z", - "estimated" : null } }, "route" : null, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index cc93ffb211c..39877eef0b7 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -25,13 +25,6 @@ name lat lon - arrival { - scheduledTime - estimated { - time - delay - } - } departure { scheduledTime estimated { @@ -51,13 +44,6 @@ delay } } - departure { - scheduledTime - estimated { - time - delay - } - } } route { gtfsId From 38f7dfaae5f8f826159e7b05df49be13e6bcf98b Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 10:57:42 +0100 Subject: [PATCH 49/83] Update docs --- .../java/org/opentripplanner/framework/lang/StringUtils.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java index 1e57fb55027..9eff448d0c7 100644 --- a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java +++ b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java @@ -134,11 +134,10 @@ public static String kebabCase(String input) { } /** - * Removes unprintable control characters like newlines, tabs and invisible whitespace + * Detects unprintable control characters like newlines, tabs and invisible whitespace * like 'ZERO WIDTH SPACE' (U+200B) that don't have an immediate visual representation. *

- * Note that "regular" whitespace characters like U+0020 and U+2000 are considered visible and - * therefore not removed. + * Note that "regular" whitespace characters like U+0020 and U+2000 are considered visible. */ public static boolean containsInvisibleCharacters(String input) { return INVISIBLE_CHARS_PATTERN.matcher(input).find(); From 5bf60ef3b90547a4016ab84c7800c4d23a205fc7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 1 Mar 2024 23:00:51 +0100 Subject: [PATCH 50/83] 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 2bd2026116177d6bc0c55f1f5da1eb5bd9fef403 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 14:50:27 +0100 Subject: [PATCH 51/83] Add validation Co-authored-by: Thomas Gran --- .../org/opentripplanner/model/plan/StopArrivalMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java index 3a907e8cffb..9f8e4f7045a 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -16,9 +16,9 @@ class StopArrivalMapper { private final TripTimes tripTimes; public StopArrivalMapper(ZoneId zoneId, LocalDate serviceDate, TripTimes tripTimes) { - this.zoneId = zoneId; - this.serviceDate = serviceDate; - this.tripTimes = tripTimes; + this.zoneId = Objects.requireNonNull(zoneId); + this.serviceDate = Objects.requireNonNull(serviceDate); + this.tripTimes = Objects.requireNonNull(tripTimes); } StopArrival map(int i, StopLocation stop, boolean realTime) { From a9406dc1baf835eb69b3539fbbe8b9e5db485ed5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 14:57:31 +0100 Subject: [PATCH 52/83] Add import --- .../java/org/opentripplanner/model/plan/StopArrivalMapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java index 9f8e4f7045a..25bab2a7c3f 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -2,6 +2,7 @@ import java.time.LocalDate; import java.time.ZoneId; +import java.util.Objects; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.TripTimes; From 964a3f767d6196524126102fbd46006427a3a7e5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 15:04:40 +0100 Subject: [PATCH 53/83] Use uppercase for constants --- .../opentripplanner/apis/gtfs/GraphQLScalars.java | 12 ++++++------ .../opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 12 ++++++------ .../apis/gtfs/DurationScalarTest.java | 4 ++-- .../opentripplanner/apis/gtfs/GeoJsonScalarTest.java | 2 +- .../apis/gtfs/OffsetDateTimeScalarTest.java | 6 +++--- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index f0e4f295055..9a9d704afdb 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -25,9 +25,9 @@ public class GraphQLScalars { private static final ObjectMapper geoJsonMapper = new ObjectMapper() .registerModule(new JtsModule(GeometryUtils.getGeometryFactory())); - public static GraphQLScalarType durationScalar = DurationScalarFactory.createDurationScalar(); + public static GraphQLScalarType DURATION_SCALAR = DurationScalarFactory.createDurationScalar(); - public static final GraphQLScalarType polylineScalar = GraphQLScalarType + public static final GraphQLScalarType POLYLINE_SCALAR = GraphQLScalarType .newScalar() .name("Polyline") .description( @@ -56,7 +56,7 @@ public String parseLiteral(Object input) { ) .build(); - public static final GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType + public static final GraphQLScalarType OFFSET_DATETIME_SCALAR = GraphQLScalarType .newScalar() .name("OffsetDateTime") .coercing( @@ -112,7 +112,7 @@ public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralExce ) .build(); - public static final GraphQLScalarType geoJsonScalar = GraphQLScalarType + public static final GraphQLScalarType GEOJSON_SCALAR = GraphQLScalarType .newScalar() .name("GeoJson") .description("Geographic data structures in JSON format. See: https://geojson.org/") @@ -140,7 +140,7 @@ public Geometry parseLiteral(Object input) throws CoercingParseLiteralException ) .build(); - public static final GraphQLScalarType graphQLIDScalar = GraphQLScalarType + public static final GraphQLScalarType GRAPHQLID_SCALAR = GraphQLScalarType .newScalar() .name("ID") .coercing( @@ -180,7 +180,7 @@ public Relay.ResolvedGlobalId parseLiteral(Object input) ) .build(); - public static final GraphQLScalarType gramsScalar = GraphQLScalarType + public static final GraphQLScalarType GRAMS_SCALAR = GraphQLScalarType .newScalar() .name("Grams") .coercing( diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 0d76de16dc1..6adadaa40ff 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -106,12 +106,12 @@ protected static GraphQLSchema buildSchema() { IntrospectionTypeWiring typeWiring = new IntrospectionTypeWiring(typeRegistry); RuntimeWiring runtimeWiring = RuntimeWiring .newRuntimeWiring() - .scalar(GraphQLScalars.durationScalar) - .scalar(GraphQLScalars.polylineScalar) - .scalar(GraphQLScalars.geoJsonScalar) - .scalar(GraphQLScalars.graphQLIDScalar) - .scalar(GraphQLScalars.gramsScalar) - .scalar(GraphQLScalars.offsetDateTimeScalar) + .scalar(GraphQLScalars.DURATION_SCALAR) + .scalar(GraphQLScalars.POLYLINE_SCALAR) + .scalar(GraphQLScalars.GEOJSON_SCALAR) + .scalar(GraphQLScalars.GRAPHQLID_SCALAR) + .scalar(GraphQLScalars.GRAMS_SCALAR) + .scalar(GraphQLScalars.OFFSET_DATETIME_SCALAR) .scalar(ExtendedScalars.GraphQLLong) .type("Node", type -> type.typeResolver(new NodeTypeResolver())) .type("PlaceInterface", type -> type.typeResolver(new PlaceInterfaceTypeResolver())) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java index ca87311ac3a..28d1ad08376 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java @@ -27,7 +27,7 @@ static List durationCases() { @ParameterizedTest @MethodSource("durationCases") void duration(Duration duration, String expected) { - var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); + var string = GraphQLScalars.DURATION_SCALAR.getCoercing().serialize(duration); assertEquals(expected, string); } @@ -35,7 +35,7 @@ void duration(Duration duration, String expected) { void nonDuration() { Assertions.assertThrows( CoercingSerializeException.class, - () -> GraphQLScalars.durationScalar.getCoercing().serialize(new Object()) + () -> GraphQLScalars.DURATION_SCALAR.getCoercing().serialize(new Object()) ); } } diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java index 92188e603c4..cc88e22d074 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java @@ -21,7 +21,7 @@ void geoJson() throws JsonProcessingException { new Coordinate(0, 0), } ); - var geoJson = GraphQLScalars.geoJsonScalar.getCoercing().serialize(polygon); + var geoJson = GraphQLScalars.GEOJSON_SCALAR.getCoercing().serialize(polygon); var jsonNode = ObjectMappers .ignoringExtraFields() diff --git a/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java index 890bf1eeed1..45c8e9de837 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java @@ -40,21 +40,21 @@ static List offsetDateTimeCases() { @ParameterizedTest @MethodSource("offsetDateTimeCases") void serializeOffsetDateTime(OffsetDateTime odt, String expected) { - var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + var string = GraphQLScalars.OFFSET_DATETIME_SCALAR.getCoercing().serialize(odt); assertEquals(expected, string); } @ParameterizedTest @MethodSource("offsetDateTimeCases") void parseOffsetDateTime(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); + var odt = GraphQLScalars.OFFSET_DATETIME_SCALAR.getCoercing().parseValue(input); assertEquals(expected, odt); } @ParameterizedTest @MethodSource("offsetDateTimeCases") void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar + var odt = GraphQLScalars.OFFSET_DATETIME_SCALAR .getCoercing() .parseLiteral(new StringValue(input)); assertEquals(expected, odt); From 993bdb15884fbb23ef828b1ff580c70bb4d286e4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 17:03:10 +0100 Subject: [PATCH 54/83] Add user agent to OTP HTTP client --- .../java/org/opentripplanner/framework/io/OtpHttpClient.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java b/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java index 72b67441a18..2d53861f523 100644 --- a/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java +++ b/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java @@ -36,6 +36,7 @@ import org.apache.hc.core5.pool.PoolReusePolicy; import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.Timeout; +import org.opentripplanner.model.projectinfo.OtpProjectInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -138,6 +139,7 @@ private OtpHttpClient(Duration timeout, Duration connectionTtl, int maxConnectio HttpClientBuilder httpClientBuilder = HttpClients .custom() + .setUserAgent("OpenTripPlanner %s".formatted(OtpProjectInfo.projectInfo().version.toString())) .setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig(timeout)); From 6c956b86f392865fc2e7a82425e195c62374f015 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 5 Mar 2024 12:07:32 +0100 Subject: [PATCH 55/83] Remove version number --- .../java/org/opentripplanner/framework/io/OtpHttpClient.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java b/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java index 2d53861f523..c922cfcc4be 100644 --- a/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java +++ b/src/main/java/org/opentripplanner/framework/io/OtpHttpClient.java @@ -36,7 +36,6 @@ import org.apache.hc.core5.pool.PoolReusePolicy; import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.Timeout; -import org.opentripplanner.model.projectinfo.OtpProjectInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -139,7 +138,7 @@ private OtpHttpClient(Duration timeout, Duration connectionTtl, int maxConnectio HttpClientBuilder httpClientBuilder = HttpClients .custom() - .setUserAgent("OpenTripPlanner %s".formatted(OtpProjectInfo.projectInfo().version.toString())) + .setUserAgent("OpenTripPlanner") .setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig(timeout)); From 2f763e9626a89164f09d73030bdccb09590650d1 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 5 Mar 2024 12:30:19 +0100 Subject: [PATCH 56/83] Rename constant --- src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java | 2 +- .../java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 9a9d704afdb..42ffe992539 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -140,7 +140,7 @@ public Geometry parseLiteral(Object input) throws CoercingParseLiteralException ) .build(); - public static final GraphQLScalarType GRAPHQLID_SCALAR = GraphQLScalarType + public static final GraphQLScalarType GRAPHQL_ID_SCALAR = GraphQLScalarType .newScalar() .name("ID") .coercing( diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 6adadaa40ff..1fd78765a07 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -109,7 +109,7 @@ protected static GraphQLSchema buildSchema() { .scalar(GraphQLScalars.DURATION_SCALAR) .scalar(GraphQLScalars.POLYLINE_SCALAR) .scalar(GraphQLScalars.GEOJSON_SCALAR) - .scalar(GraphQLScalars.GRAPHQLID_SCALAR) + .scalar(GraphQLScalars.GRAPHQL_ID_SCALAR) .scalar(GraphQLScalars.GRAMS_SCALAR) .scalar(GraphQLScalars.OFFSET_DATETIME_SCALAR) .scalar(ExtendedScalars.GraphQLLong) From 4cdd8be12443cc134f2285d64fb5636ce10cf585 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 5 Mar 2024 16:04:06 +0100 Subject: [PATCH 57/83] 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 58/83] 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 59/83] 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 60/83] 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 61/83] 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 62/83] 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 63/83] 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 a58862dbe628b3fcf28e87dbdbee376cd1de1591 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 7 Mar 2024 18:31:59 +0100 Subject: [PATCH 64/83] Fix formatting --- .../org/opentripplanner/framework/lang/StringUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java index 249fe4a611e..0e67344b2bb 100644 --- a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java @@ -11,8 +11,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.ValueSource; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; class StringUtilsTest { 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 65/83] 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 From f47cface35418a26e4c394395e4d964a285847ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 18:53:20 +0000 Subject: [PATCH 66/83] fix(deps): update dependency ch.poole:openinghoursparser to v0.28.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3248cfede87..59f4579f633 100644 --- a/pom.xml +++ b/pom.xml @@ -923,7 +923,7 @@ ch.poole OpeningHoursParser - 0.28.1 + 0.28.2 From 3a7c610c9b8efddf5d897c4de523b507730072e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 10:40:19 +0000 Subject: [PATCH 67/83] fix(deps): update jackson.version to v2.16.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a087b091d46..d74b767a060 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 30.2 2.51 - 2.16.1 + 2.16.2 3.1.5 5.10.2 1.12.3 From 747246e79218fca148f9975e414e69b8d7988792 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 8 Mar 2024 17:46:32 +0100 Subject: [PATCH 68/83] Fix two bugs in the WorldEnvelope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The envelope calculation was wrong when envelope included0º (Greenwich) - The medianCenter was wrong when the envelope included 180º --- .../worldenvelope/model/WorldEnvelope.java | 23 ++- .../model/WorldEnvelopeBuilder.java | 44 ++++-- .../model/WorldEnvelopeTest.java | 142 ++++++++++-------- 3 files changed, 126 insertions(+), 83 deletions(-) diff --git a/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelope.java b/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelope.java index 8d211fd33db..27a1fb4d30f 100644 --- a/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelope.java +++ b/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelope.java @@ -6,8 +6,7 @@ import org.opentripplanner.framework.tostring.ToStringBuilder; /** - * This class calculates borders of envelopes that can be also on 180th meridian The same way as it - * was previously calculated in GraphMetadata constructor + * This class calculates borders of envelopes that can be also on 180th meridian. */ public class WorldEnvelope implements Serializable { @@ -53,14 +52,6 @@ public WgsCoordinate upperRight() { return upperRight; } - /** - * This is the center of the Envelope including both street vertexes and transit stops - * if they exist. - */ - public WgsCoordinate meanCenter() { - return meanCenter; - } - /** * If transit data exist, then this is the median center of the transit stops. The median * is computed independently for the longitude and latitude. @@ -68,13 +59,21 @@ public WgsCoordinate meanCenter() { * If not transit data exist this return `empty`. */ public WgsCoordinate center() { - return transitMedianCenter().orElse(meanCenter); + return medianCenter().orElse(meanCenter); + } + + /** + * This is the center of the Envelope including both street vertexes and transit stops + * if they exist. + */ + public WgsCoordinate meanCenter() { + return meanCenter; } /** * Return the transit median center [if it exist] or the mean center. */ - public Optional transitMedianCenter() { + public Optional medianCenter() { return Optional.ofNullable(transitMedianCenter); } diff --git a/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeBuilder.java b/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeBuilder.java index abddba9c5fd..7c5bf13d5e5 100644 --- a/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeBuilder.java +++ b/src/main/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeBuilder.java @@ -58,8 +58,23 @@ public WorldEnvelopeBuilder expandToIncludeTransitEntities( var medianCalculator = new MedianCalcForDoubles(collection.size()); - collection.forEach(v -> medianCalculator.add(lonProvider.apply(v))); - double lon = medianCalculator.median(); + double lon = 0.0; + if (includeLongitude180()) { + collection.forEach(v -> { + double c = lonProvider.apply(v); + if (c < 0) { + c += 360.0; + } + medianCalculator.add(c); + }); + lon = medianCalculator.median(); + if (lon > 180.0) { + lon -= 180; + } + } else { + collection.forEach(v -> medianCalculator.add(lonProvider.apply(v))); + lon = medianCalculator.median(); + } medianCalculator.reset(); collection.forEach(v -> medianCalculator.add(latProvider.apply(v))); @@ -79,19 +94,26 @@ public WorldEnvelope build() { if (minLonEast == MIN_NOT_SET) { return new WorldEnvelope(minLat, minLonWest, maxLat, maxLonWest, transitMedianCenter); } - // Envelope intersects with either 0º or 180º - double dist0 = minLonEast - minLonWest; - double dist180 = 360d - maxLonEast + minLonWest; - - // A small gap between the east and west longitude at 0 degrees implies that the Envelope - // should include the 0 degrees longitude(meridian), and be split at 180 degrees. - if (dist0 < dist180) { - return new WorldEnvelope(minLat, maxLonWest, maxLat, maxLonEast, transitMedianCenter); - } else { + if (includeLongitude180()) { return new WorldEnvelope(minLat, minLonEast, maxLat, minLonWest, transitMedianCenter); + } else { + return new WorldEnvelope(minLat, minLonWest, maxLat, maxLonEast, transitMedianCenter); } } + /** + * A small gap between the east and west longitude at 180º degrees implies that the Envelope + * should include the 180º longitude, and be split at 0 degrees. + */ + boolean includeLongitude180() { + if (minLonWest == MIN_NOT_SET || minLonEast == MIN_NOT_SET) { + return false; + } + double dist0 = minLonEast - minLonWest; + double dist180 = 360d - maxLonEast + minLonWest; + return dist180 < dist0; + } + private WorldEnvelopeBuilder expandToInclude(double latitude, double longitude) { minLat = Math.min(minLat, latitude); maxLat = Math.max(maxLat, latitude); diff --git a/src/test/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeTest.java b/src/test/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeTest.java index bff99800fdb..136caf31a5b 100644 --- a/src/test/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeTest.java +++ b/src/test/java/org/opentripplanner/service/worldenvelope/model/WorldEnvelopeTest.java @@ -5,6 +5,9 @@ import java.util.List; 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.geometry.WgsCoordinate; class WorldEnvelopeTest { @@ -18,83 +21,102 @@ class WorldEnvelopeTest { private static final int W60 = -60; private static final int W170 = -170; - private static final WorldEnvelope EAST = WorldEnvelope - .of() - .expandToIncludeStreetEntities(S10, E50) - .expandToIncludeStreetEntities(S20, E160) - .build(); - private static final WorldEnvelope WEST = WorldEnvelope - .of() - .expandToIncludeStreetEntities(N30, W60) - .expandToIncludeStreetEntities(N40, W170) - .build(); - private static final WorldEnvelope GREENWICH = WorldEnvelope - .of() - .expandToIncludeStreetEntities(N30, W60) - .expandToIncludeStreetEntities(S10, E50) - .build(); - private static final WorldEnvelope MERIDIAN_180 = WorldEnvelope - .of() - .expandToIncludeStreetEntities(N40, W170) - .expandToIncludeStreetEntities(S20, E160) - .build(); - - @Test - void testEast() { - var expectedCenter = new WgsCoordinate(-15d, 105d); - - assertEquals(S20, EAST.lowerLeft().latitude()); - assertEquals(E50, EAST.lowerLeft().longitude()); - assertEquals(S10, EAST.upperRight().latitude()); - assertEquals(E160, EAST.upperRight().longitude()); - assertEquals(expectedCenter, EAST.meanCenter()); - assertEquals(expectedCenter, EAST.center()); - assertTrue(EAST.transitMedianCenter().isEmpty()); + /** + * To make sure we cover all cases we add a case for each combination of: + * - latitude + * - south hemisphere + * - north hemisphere + * - both sides of the equator + * - longitude + * - east side of 0º (Greenwich) + * - west side of 0º + * - both sides of 0º + * - both sides of 180º + * Skip cases for North- and South-pole - not relevant - obscure cases) + */ + static List testCases() { + return List.of( + // name, lower-lat, left-lon, upper-lat, right-lon, center-lat, center-lon + Arguments.of("South-East", S20, E50, S10, E160, -15d, 105d), + Arguments.of("Equator-East", S10, E50, N30, E160, 10d, 105d), + Arguments.of("North-East", N30, E50, N40, E160, 35d, 105d), + Arguments.of("South-West", S20, W170, S10, W60, -15d, -115d), + Arguments.of("Equator-West", S10, W170, N30, W60, 10d, -115d), + Arguments.of("North-West", N30, W170, N40, W60, 35d, -115d), + Arguments.of("North-Greenwich", N30, W60, N40, E50, 35d, -5d), + Arguments.of("Equator-Greenwich", S10, W60, N30, E50, 10d, -5d), + Arguments.of("South-Greenwich", S20, W60, S10, E50, -15d, -5d), + Arguments.of("North-180º", N30, E160, N40, W170, 35d, 175d), + Arguments.of("Equator-180º", S10, E160, N30, W170, 10d, 175d), + Arguments.of("South-180º", S20, E160, S10, W170, -15d, 175d) + ); } - @Test - void transitMedianCenter() { - var expectedCenter = new WgsCoordinate(S10, E50); + @ParameterizedTest + @MethodSource("testCases") + void testWorldEnvelope( + String name, + double lowerLat, + double leftLon, + double upperLat, + double rightLon, + double centerLat, + double centerLon + ) { + // Add a point close to the center + var median = new WgsCoordinate(centerLat + 1.0, centerLon + 1.0); - var subject = WorldEnvelope + // WorldEnvelope should normalize to lower-left and upper-right + // Add lower-right & upper-left the world-envelope + var subjectWithoutMedian = WorldEnvelope + .of() + .expandToIncludeStreetEntities(lowerLat, rightLon) + .expandToIncludeStreetEntities(upperLat, leftLon) + .build(); + // Add the ~middle point between each corner of the envelope + median point + // We offset the one center value to the "other" side of the median by adding 2.0 + var subjectWithMedian = WorldEnvelope .of() .expandToIncludeTransitEntities( List.of( - new WgsCoordinate(S10, E50), - new WgsCoordinate(S20, E160), - new WgsCoordinate(N40, W60) + new WgsCoordinate(upperLat, centerLon), + new WgsCoordinate(lowerLat, centerLon + 2d), + new WgsCoordinate(centerLat, rightLon), + new WgsCoordinate(centerLat + 2d, leftLon), + median ), WgsCoordinate::latitude, WgsCoordinate::longitude ) .build(); - assertTrue(subject.transitMedianCenter().isPresent(), subject.transitMedianCenter().toString()); - assertEquals(expectedCenter, subject.transitMedianCenter().get()); - assertEquals(expectedCenter, subject.center()); - assertEquals( - "WorldEnvelope{lowerLeft: (-20.0, -60.0), upperRight: (40.0, 160.0), meanCenter: (10.0, 50.0), transitMedianCenter: (-10.0, 50.0)}", - subject.toString() + for (WorldEnvelope subject : List.of(subjectWithoutMedian, subjectWithMedian)) { + assertEquals(lowerLat, subject.lowerLeft().latitude(), name + " lower-latitude"); + assertEquals(leftLon, subject.lowerLeft().longitude(), name + " left-longitude"); + assertEquals(upperLat, subject.upperRight().latitude(), name + " upper-latitude"); + assertEquals(rightLon, subject.upperRight().longitude(), name + " right-longitude"); + assertEquals(centerLat, subject.meanCenter().latitude(), name + " center-latitude"); + assertEquals(centerLon, subject.meanCenter().longitude(), name + " center-longitude"); + } + + assertTrue( + subjectWithoutMedian.medianCenter().isEmpty(), + "First envelope does not have a median" ); + assertTrue(subjectWithMedian.medianCenter().isPresent(), "Second envelope does have a median"); + assertEquals(median, subjectWithMedian.medianCenter().get(), name + " median"); } @Test - void testToString() { - assertEquals( - "WorldEnvelope{lowerLeft: (-20.0, 50.0), upperRight: (-10.0, 160.0), meanCenter: (-15.0, 105.0)}", - EAST.toString() - ); - assertEquals( - "WorldEnvelope{lowerLeft: (30.0, -170.0), upperRight: (40.0, -60.0), meanCenter: (35.0, -115.0)}", - WEST.toString() - ); - assertEquals( - "WorldEnvelope{lowerLeft: (-10.0, -60.0), upperRight: (30.0, 50.0), meanCenter: (10.0, -5.0)}", - GREENWICH.toString() - ); + void testWorldEnvelopeToString() { assertEquals( - "WorldEnvelope{lowerLeft: (-20.0, 160.0), upperRight: (40.0, -170.0), meanCenter: (10.0, 175.0)}", - MERIDIAN_180.toString() + "WorldEnvelope{lowerLeft: (-10.0, -60.0), upperRight: (40.0, 50.0), meanCenter: (15.0, -5.0)}", + WorldEnvelope + .of() + .expandToIncludeStreetEntities(S10, E50) + .expandToIncludeStreetEntities(N40, W60) + .build() + .toString() ); } } From 0bd241c55d9b4b84dbbd6be76a8e92c6018a29e9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 01:01:35 +0000 Subject: [PATCH 69/83] chore(deps): update debug ui dependencies (non-major) --- client-next/package-lock.json | 999 +++++++++++++++++++++------------- client-next/package.json | 48 +- 2 files changed, 630 insertions(+), 417 deletions(-) diff --git a/client-next/package-lock.json b/client-next/package-lock.json index 7f01598ad30..944da10aa11 100644 --- a/client-next/package-lock.json +++ b/client-next/package-lock.json @@ -9,39 +9,39 @@ "version": "0.0.0", "dependencies": { "@googlemaps/polyline-codec": "1.0.28", - "bootstrap": "5.3.1", + "bootstrap": "5.3.3", "graphql": "16.8.1", "graphql-request": "6.1.0", - "maplibre-gl": "4.0.1", + "maplibre-gl": "4.1.0", "react": "18.2.0", - "react-bootstrap": "2.8.0", + "react-bootstrap": "2.10.1", "react-dom": "18.2.0", - "react-map-gl": "7.1.5" + "react-map-gl": "7.1.7" }, "devDependencies": { - "@graphql-codegen/cli": "5.0.0", - "@graphql-codegen/client-preset": "4.1.0", - "@graphql-codegen/introspection": "4.0.0", - "@parcel/watcher": "2.3.0", - "@testing-library/react": "14.1.2", - "@types/react": "18.2.21", - "@types/react-dom": "18.2.7", - "@typescript-eslint/eslint-plugin": "7.1.0", - "@typescript-eslint/parser": "7.1.0", - "@vitejs/plugin-react": "4.0.4", - "@vitest/coverage-v8": "1.1.3", - "eslint": "8.56.0", - "eslint-config-prettier": "9.0.0", - "eslint-plugin-import": "2.28.1", - "eslint-plugin-jsx-a11y": "6.7.1", - "eslint-plugin-react": "7.33.2", + "@graphql-codegen/cli": "5.0.2", + "@graphql-codegen/client-preset": "4.2.4", + "@graphql-codegen/introspection": "4.0.3", + "@parcel/watcher": "2.4.1", + "@testing-library/react": "14.2.1", + "@types/react": "18.2.65", + "@types/react-dom": "18.2.21", + "@typescript-eslint/eslint-plugin": "7.2.0", + "@typescript-eslint/parser": "7.2.0", + "@vitejs/plugin-react": "4.2.1", + "@vitest/coverage-v8": "1.3.1", + "eslint": "8.57.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsx-a11y": "6.8.0", + "eslint-plugin-react": "7.34.0", "eslint-plugin-react-hooks": "4.6.0", - "eslint-plugin-react-refresh": "0.4.3", + "eslint-plugin-react-refresh": "0.4.5", "jsdom": "24.0.0", - "prettier": "3.0.3", - "typescript": "5.2.2", + "prettier": "3.2.5", + "typescript": "5.4.2", "vite": "4.5.2", - "vitest": "1.1.3" + "vitest": "1.3.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -380,9 +380,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", - "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.0.tgz", + "integrity": "sha512-QAH+vfvts51BCsNZ2PhY6HAggnlS6omLLFTsIpeqZk/MmJ6cW7tgz5yRv0fMJThcr6FmbMrENh1RgrWPTYA76g==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -1656,9 +1656,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1683,16 +1683,17 @@ } }, "node_modules/@graphql-codegen/cli": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-5.0.0.tgz", - "integrity": "sha512-A7J7+be/a6e+/ul2KI5sfJlpoqeqwX8EzktaKCeduyVKgOLA6W5t+NUGf6QumBDXU8PEOqXk3o3F+RAwCWOiqA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-5.0.2.tgz", + "integrity": "sha512-MBIaFqDiLKuO4ojN6xxG9/xL9wmfD3ZjZ7RsPjwQnSHBCUXnEkdKvX+JVpx87Pq29Ycn8wTJUguXnTZ7Di0Mlw==", "dev": true, "dependencies": { "@babel/generator": "^7.18.13", "@babel/template": "^7.18.10", "@babel/types": "^7.18.13", - "@graphql-codegen/core": "^4.0.0", - "@graphql-codegen/plugin-helpers": "^5.0.1", + "@graphql-codegen/client-preset": "^4.2.2", + "@graphql-codegen/core": "^4.0.2", + "@graphql-codegen/plugin-helpers": "^5.0.3", "@graphql-tools/apollo-engine-loader": "^8.0.0", "@graphql-tools/code-file-loader": "^8.0.0", "@graphql-tools/git-loader": "^8.0.0", @@ -1740,35 +1741,29 @@ } }, "node_modules/@graphql-codegen/client-preset": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.1.0.tgz", - "integrity": "sha512-/3Ymb/fjxIF1+HGmaI1YwSZbWsrZAWMSQjh3dU425eBjctjsVQ6gzGRr+l/gE5F1mtmCf+vlbTAT03heAc/QIw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.2.4.tgz", + "integrity": "sha512-k1c8v2YxJhhITGQGxViG9asLAoop9m7X9duU7Zztqjc98ooxsUzXICfvAWsH3mLAUibXAx4Ax6BPzKsTtQmBPg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", - "@graphql-codegen/add": "^5.0.0", - "@graphql-codegen/gql-tag-operations": "4.0.1", - "@graphql-codegen/plugin-helpers": "^5.0.1", - "@graphql-codegen/typed-document-node": "^5.0.1", - "@graphql-codegen/typescript": "^4.0.1", - "@graphql-codegen/typescript-operations": "^4.0.1", - "@graphql-codegen/visitor-plugin-common": "^4.0.1", + "@graphql-codegen/add": "^5.0.2", + "@graphql-codegen/gql-tag-operations": "4.0.6", + "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-codegen/typed-document-node": "^5.0.6", + "@graphql-codegen/typescript": "^4.0.6", + "@graphql-codegen/typescript-operations": "^4.2.0", + "@graphql-codegen/visitor-plugin-common": "^5.1.0", "@graphql-tools/documents": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-typed-document-node/core": "3.2.0", - "tslib": "~2.5.0" + "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/@graphql-codegen/client-preset/node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", - "dev": true - }, "node_modules/@graphql-codegen/core": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-4.0.2.tgz", @@ -1785,68 +1780,35 @@ } }, "node_modules/@graphql-codegen/gql-tag-operations": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.1.tgz", - "integrity": "sha512-qF6wIbBzW8BNT+wiVsBxrYOs2oYcsxQ7mRvCpfEI3HnNZMAST/uX76W8MqFEJvj4mw7NIDv7xYJAcAZIWM5LWw==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.6.tgz", + "integrity": "sha512-y6iXEDpDNjwNxJw3WZqX1/Znj0QHW7+y8O+t2V8qvbTT+3kb2lr9ntc8By7vCr6ctw9tXI4XKaJgpTstJDOwFA==", "dev": true, "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.0.0", - "@graphql-codegen/visitor-plugin-common": "4.0.1", - "@graphql-tools/utils": "^10.0.0", - "auto-bind": "~4.0.0", - "tslib": "~2.5.0" - }, - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/@graphql-codegen/gql-tag-operations/node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-4.0.1.tgz", - "integrity": "sha512-Bi/1z0nHg4QMsAqAJhds+ForyLtk7A3HQOlkrZNm3xEkY7lcBzPtiOTLBtvziwopBsXUxqeSwVjOOFPLS5Yw1Q==", - "dev": true, - "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.0.0", - "@graphql-tools/optimize": "^2.0.0", - "@graphql-tools/relay-operation-optimizer": "^7.0.0", + "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-codegen/visitor-plugin-common": "5.1.0", "@graphql-tools/utils": "^10.0.0", "auto-bind": "~4.0.0", - "change-case-all": "1.0.15", - "dependency-graph": "^0.11.0", - "graphql-tag": "^2.11.0", - "parse-filepath": "^1.0.2", - "tslib": "~2.5.0" + "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/@graphql-codegen/gql-tag-operations/node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", - "dev": true - }, "node_modules/@graphql-codegen/introspection": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-4.0.0.tgz", - "integrity": "sha512-t9g3AkK99dfHblMWtG4ynUM9+A7JrWq5110zSpNV2wlSnv0+bRKagDW8gozwgXfR5i1IIG8QDjJZ6VgXQVqCZw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-4.0.3.tgz", + "integrity": "sha512-4cHRG15Zu4MXMF4wTQmywNf4+fkDYv5lTbzraVfliDnB8rJKcaurQpRBi11KVuQUe24YTq/Cfk4uwewfNikWoA==", "dev": true, "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.0.0", - "@graphql-codegen/visitor-plugin-common": "^4.0.0", - "tslib": "~2.5.0" + "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-codegen/visitor-plugin-common": "^5.0.0", + "tslib": "~2.6.0" }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/@graphql-codegen/introspection/node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", - "dev": true - }, "node_modules/@graphql-codegen/plugin-helpers": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.0.3.tgz", @@ -1879,13 +1841,13 @@ } }, "node_modules/@graphql-codegen/typed-document-node": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.4.tgz", - "integrity": "sha512-t66Z6erQ4Dh1j6f9pRZmc8uYtHoUI3A49tLmJAlg9/3IV0kCmwrWKJut/G8SeOefDLG8cXBTVtI/YuZOe1Te+w==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.6.tgz", + "integrity": "sha512-US0J95hOE2/W/h42w4oiY+DFKG7IetEN1mQMgXXeat1w6FAR5PlIz4JrRrEkiVfVetZ1g7K78SOwBD8/IJnDiA==", "dev": true, "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", - "@graphql-codegen/visitor-plugin-common": "4.1.2", + "@graphql-codegen/visitor-plugin-common": "5.1.0", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", "tslib": "~2.6.0" @@ -1895,14 +1857,14 @@ } }, "node_modules/@graphql-codegen/typescript": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.0.4.tgz", - "integrity": "sha512-x79CKLfP9UQCX+/I78qxQlMs2Mmq3pF1lKafZo7lAno0f/fvJ+qWUduzdgjRNz+YL+5blGeWcC0pWEDxniO7hw==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.0.6.tgz", + "integrity": "sha512-IBG4N+Blv7KAL27bseruIoLTjORFCT3r+QYyMC3g11uY3/9TPpaUyjSdF70yBe5GIQ6dAgDU+ENUC1v7EPi0rw==", "dev": true, "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", "@graphql-codegen/schema-ast": "^4.0.2", - "@graphql-codegen/visitor-plugin-common": "4.1.2", + "@graphql-codegen/visitor-plugin-common": "5.1.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -1911,14 +1873,14 @@ } }, "node_modules/@graphql-codegen/typescript-operations": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.1.2.tgz", - "integrity": "sha512-CtCWK+gW7hS+Ely3lohr8CL1HVLswQzMcaUk3k1sxdWCWKTNq7abMsWa31rTVwRCJ+WNEkM/7S8sIBTpEG683A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.2.0.tgz", + "integrity": "sha512-lmuwYb03XC7LNRS8oo9M4/vlOrq/wOKmTLBHlltK2YJ1BO/4K/Q9Jdv/jDmJpNydHVR1fmeF4wAfsIp1f9JibA==", "dev": true, "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", - "@graphql-codegen/typescript": "^4.0.4", - "@graphql-codegen/visitor-plugin-common": "4.1.2", + "@graphql-codegen/typescript": "^4.0.6", + "@graphql-codegen/visitor-plugin-common": "5.1.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -1927,9 +1889,9 @@ } }, "node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-4.1.2.tgz", - "integrity": "sha512-yk7iEAL1kYZ2Gi/pvVjdsZhul5WsYEM4Zcgh2Ev15VicMdJmPHsMhNUsZWyVJV0CaQCYpNOFlGD/11Ea3pn4GA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.1.0.tgz", + "integrity": "sha512-eamQxtA9bjJqI2lU5eYoA1GbdMIRT2X8m8vhWYsVQVWD3qM7sx/IqJU0kx0J3Vd4/CSd36BzL6RKwksibytDIg==", "dev": true, "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", @@ -2491,13 +2453,13 @@ "dev": true }, "node_modules/@graphql-tools/relay-operation-optimizer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.0.tgz", - "integrity": "sha512-UNlJi5y3JylhVWU4MBpL0Hun4Q7IoJwv9xYtmAz+CgRa066szzY7dcuPfxrA7cIGgG/Q6TVsKsYaiF4OHPs1Fw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.1.tgz", + "integrity": "sha512-y0ZrQ/iyqWZlsS/xrJfSir3TbVYJTYmMOu4TaSz6F4FRDTQ3ie43BlKkhf04rC28pnUOS4BO9pDcAo1D30l5+A==", "dev": true, "dependencies": { "@ardatan/relay-compiler": "12.0.0", - "@graphql-tools/utils": "^10.0.0", + "@graphql-tools/utils": "^10.0.13", "tslib": "^2.4.0" }, "engines": { @@ -2854,11 +2816,10 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz", - "integrity": "sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz", + "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==", "dev": true, - "hasInstallScript": true, "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", @@ -2873,24 +2834,24 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.3.0", - "@parcel/watcher-darwin-arm64": "2.3.0", - "@parcel/watcher-darwin-x64": "2.3.0", - "@parcel/watcher-freebsd-x64": "2.3.0", - "@parcel/watcher-linux-arm-glibc": "2.3.0", - "@parcel/watcher-linux-arm64-glibc": "2.3.0", - "@parcel/watcher-linux-arm64-musl": "2.3.0", - "@parcel/watcher-linux-x64-glibc": "2.3.0", - "@parcel/watcher-linux-x64-musl": "2.3.0", - "@parcel/watcher-win32-arm64": "2.3.0", - "@parcel/watcher-win32-ia32": "2.3.0", - "@parcel/watcher-win32-x64": "2.3.0" + "@parcel/watcher-android-arm64": "2.4.1", + "@parcel/watcher-darwin-arm64": "2.4.1", + "@parcel/watcher-darwin-x64": "2.4.1", + "@parcel/watcher-freebsd-x64": "2.4.1", + "@parcel/watcher-linux-arm-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-musl": "2.4.1", + "@parcel/watcher-linux-x64-glibc": "2.4.1", + "@parcel/watcher-linux-x64-musl": "2.4.1", + "@parcel/watcher-win32-arm64": "2.4.1", + "@parcel/watcher-win32-ia32": "2.4.1", + "@parcel/watcher-win32-x64": "2.4.1" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz", - "integrity": "sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz", + "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==", "cpu": [ "arm64" ], @@ -2908,9 +2869,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz", - "integrity": "sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", + "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==", "cpu": [ "arm64" ], @@ -2928,9 +2889,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz", - "integrity": "sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz", + "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==", "cpu": [ "x64" ], @@ -2948,9 +2909,9 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz", - "integrity": "sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz", + "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==", "cpu": [ "x64" ], @@ -2968,9 +2929,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz", - "integrity": "sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz", + "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==", "cpu": [ "arm" ], @@ -2988,9 +2949,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz", - "integrity": "sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz", + "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==", "cpu": [ "arm64" ], @@ -3008,9 +2969,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz", - "integrity": "sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==", "cpu": [ "arm64" ], @@ -3028,9 +2989,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz", - "integrity": "sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", + "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", "cpu": [ "x64" ], @@ -3048,9 +3009,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz", - "integrity": "sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==", "cpu": [ "x64" ], @@ -3068,9 +3029,9 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz", - "integrity": "sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz", + "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==", "cpu": [ "arm64" ], @@ -3088,9 +3049,9 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz", - "integrity": "sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz", + "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==", "cpu": [ "ia32" ], @@ -3108,9 +3069,9 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz", - "integrity": "sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz", + "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==", "cpu": [ "x64" ], @@ -3437,9 +3398,9 @@ } }, "node_modules/@testing-library/react": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.1.2.tgz", - "integrity": "sha512-z4p7DVBTPjKM5qDZ0t5ZjzkpSNb+fZy1u6bzO7kk8oeGagpPCAtgh4cx1syrfp7a+QWkM021jGqjJaxJJnXAZg==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.1.tgz", + "integrity": "sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -3460,6 +3421,47 @@ "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -3552,9 +3554,9 @@ "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/react": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", - "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "version": "18.2.65", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.65.tgz", + "integrity": "sha512-98TsY0aW4jqx/3RqsUXwMDZSWR1Z4CUlJNue8ueS2/wcxZOsz4xmW1X8ieaWVRHcmmQM3R8xVA4XWB3dJnWwDQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3562,9 +3564,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "version": "18.2.21", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.21.tgz", + "integrity": "sha512-gnvBA/21SA4xxqNXEwNiVcP0xSGHh/gi1VhWv9Bl46a0ItbTT5nFY+G9VSQpaG/8N/qdJpJ+vftQ4zflTtnjLw==", "dev": true, "dependencies": { "@types/react": "*" @@ -3612,16 +3614,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", - "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz", + "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/type-utils": "7.1.0", - "@typescript-eslint/utils": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/type-utils": "7.2.0", + "@typescript-eslint/utils": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3680,15 +3682,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", - "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", "debug": "^4.3.4" }, "engines": { @@ -3708,13 +3710,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", - "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", + "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0" + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3725,13 +3727,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", - "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz", + "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/utils": "7.2.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3752,9 +3754,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", + "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3765,13 +3767,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", + "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3850,17 +3852,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz", + "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", "semver": "^7.5.4" }, "engines": { @@ -3908,12 +3910,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", + "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/types": "7.2.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3931,27 +3933,28 @@ "dev": true }, "node_modules/@vitejs/plugin-react": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz", - "integrity": "sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", "dev": true, "dependencies": { - "@babel/core": "^7.22.9", - "@babel/plugin-transform-react-jsx-self": "^7.22.5", - "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.0" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0" + "vite": "^4.2.0 || ^5.0.0" } }, "node_modules/@vitest/coverage-v8": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.1.3.tgz", - "integrity": "sha512-Uput7t3eIcbSTOTQBzGtS+0kah96bX+szW9qQrLeGe3UmgL2Akn8POnyC2lH7XsnREZOds9aCUTxgXf+4HX5RA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.3.1.tgz", + "integrity": "sha512-UuBnkSJUNE9rdHjDCPyJ4fYuMkoMtnghes1XohYa4At0MS3OQSAo97FrbwSLRshYsXThMZy1+ybD/byK5llyIg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -3962,7 +3965,7 @@ "istanbul-lib-source-maps": "^4.0.1", "istanbul-reports": "^3.1.6", "magic-string": "^0.30.5", - "magicast": "^0.3.2", + "magicast": "^0.3.3", "picocolors": "^1.0.0", "std-env": "^3.5.0", "test-exclude": "^6.0.0", @@ -3972,17 +3975,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "^1.0.0" + "vitest": "1.3.1" } }, "node_modules/@vitest/expect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.1.3.tgz", - "integrity": "sha512-MnJqsKc1Ko04lksF9XoRJza0bGGwTtqfbyrsYv5on4rcEkdo+QgUdITenBQBUltKzdxW7K3rWh+nXRULwsdaVg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", + "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", "dev": true, "dependencies": { - "@vitest/spy": "1.1.3", - "@vitest/utils": "1.1.3", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", "chai": "^4.3.10" }, "funding": { @@ -3990,12 +3993,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.1.3.tgz", - "integrity": "sha512-Va2XbWMnhSdDEh/OFxyUltgQuuDRxnarK1hW5QNN4URpQrqq6jtt8cfww/pQQ4i0LjoYxh/3bYWvDFlR9tU73g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", + "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", "dev": true, "dependencies": { - "@vitest/utils": "1.1.3", + "@vitest/utils": "1.3.1", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -4031,9 +4034,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.1.3.tgz", - "integrity": "sha512-U0r8pRXsLAdxSVAyGNcqOU2H3Z4Y2dAAGGelL50O0QRMdi1WWeYHdrH/QWpN1e8juWfVKsb8B+pyJwTC+4Gy9w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", + "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -4077,9 +4080,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.1.3.tgz", - "integrity": "sha512-Ec0qWyGS5LhATFQtldvChPTAHv08yHIOZfiNcjwRQbFPHpkih0md9KAbs7TfeIfL7OFKoe7B/6ukBTqByubXkQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", + "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -4089,9 +4092,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.1.3.tgz", - "integrity": "sha512-Dyt3UMcdElTll2H75vhxfpZu03uFpXRCHxWnzcrFjZxT1kTbq8ALUYIeBgGolo1gldVdI0YSlQRacsqxTwNqwg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", + "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -4363,6 +4366,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.findlast": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.4.tgz", + "integrity": "sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.findlastindex": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", @@ -4418,6 +4440,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, "node_modules/array.prototype.tosorted": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", @@ -4491,9 +4525,9 @@ } }, "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, "node_modules/astral-regex": { @@ -4544,15 +4578,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axe-core": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.4.tgz", - "integrity": "sha512-CZLSKisu/bhJ2awW4kJndluz2HLZYIHh5Uy1+ZwDRkJi69811xgIXXfdU9HSLX0Th+ILrHj8qfL/5wzamsFtQg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -4644,9 +4669,9 @@ } }, "node_modules/bootstrap": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.1.tgz", - "integrity": "sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", "funding": [ { "type": "github", @@ -5752,16 +5777,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -5807,9 +5832,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", - "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -5865,28 +5890,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -5917,27 +5942,27 @@ } }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" }, "engines": { "node": ">=4.0" @@ -5946,28 +5971,48 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "version": "7.34.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.0.tgz", + "integrity": "sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", + "es-iterator-helpers": "^1.0.17", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", + "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" + "string.prototype.matchall": "^4.0.10" }, "engines": { "node": ">=4" @@ -5989,9 +6034,9 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.3.tgz", - "integrity": "sha512-Hh0wv8bUNY877+sI0BlCUlsS0TYYQqvzEwJsJJPM2WF4RnTStSnSR3zdJYa2nPOJgg3UghXi54lVyMSmpCalzA==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.5.tgz", + "integrity": "sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w==", "dev": true, "peerDependencies": { "eslint": ">=7" @@ -6832,15 +6877,6 @@ "graphql": ">=0.11 <=16" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -7936,12 +7972,15 @@ "dev": true }, "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dev": true, "dependencies": { - "language-subtag-registry": "~0.3.2" + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/levn": { @@ -8244,9 +8283,9 @@ } }, "node_modules/maplibre-gl": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.0.1.tgz", - "integrity": "sha512-UF+wI2utIciFXNg6+gYaMe7IGa9fMLzAZM3vdlGilqyWYmuibjcN40yGVgkz2r28//aOLphvtli3TbDEjEqHww==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.1.0.tgz", + "integrity": "sha512-4RQFJSroo/JAJml6Rj2FFIZOfnjsqPp0O9kSp8aVXQUY0HGXNupltzPKbBZeucqi7ynRQHFeu+onTM3hY0Makw==", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -9083,9 +9122,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -9242,14 +9281,14 @@ } }, "node_modules/react-bootstrap": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz", - "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.1.tgz", + "integrity": "sha512-J3OpRZIvCTQK+Tg/jOkRUvpYLHMdGeU9KqFUBQrV0d/Qr/3nsINpiOJyZMWnM5SJ3ctZdhPA6eCIKpEJR3Ellg==", "dependencies": { - "@babel/runtime": "^7.21.0", + "@babel/runtime": "^7.22.5", "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.3", - "@types/react-transition-group": "^4.4.5", + "@restart/ui": "^1.6.6", + "@types/react-transition-group": "^4.4.6", "classnames": "^2.3.2", "dom-helpers": "^5.2.1", "invariant": "^2.2.4", @@ -9294,9 +9333,9 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "node_modules/react-map-gl": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.5.tgz", - "integrity": "sha512-YS2u2cSLlZVGjfa394f0snO6f6ZwZVTKqQwjbq/jj0w7fHU01Mn+Xqvm/Qr7nZChoT3OG7kh8JluDcXeBrDG/g==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.7.tgz", + "integrity": "sha512-mwjc0obkBJOXCcoXQr3VoLqmqwo9vS4bXfbGsdxXzEgVCv/PM0v+1QggL7W0d/ccIy+VCjbXNlGij+PENz6VNg==", "dependencies": { "@maplibre/maplibre-gl-style-spec": "^19.2.1", "@types/mapbox-gl": ">=1.0.0" @@ -10132,17 +10171,23 @@ } }, "node_modules/strip-literal": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", - "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", + "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", "dev": true, "dependencies": { - "acorn": "^8.10.0" + "js-tokens": "^8.0.2" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", + "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "dev": true + }, "node_modules/supercluster": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", @@ -10478,9 +10523,9 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -10778,9 +10823,9 @@ } }, "node_modules/vite-node": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.1.3.tgz", - "integrity": "sha512-BLSO72YAkIUuNrOx+8uznYICJfTEbvBAmWClY3hpath5+h1mbPS5OMn42lrTxXuyCazVyZoDkSRnju78GiVCqA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", + "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -11277,18 +11322,17 @@ } }, "node_modules/vitest": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.1.3.tgz", - "integrity": "sha512-2l8om1NOkiA90/Y207PsEvJLYygddsOyr81wLQ20Ra8IlLKbyQncWsGZjnbkyG2KwwuTXLQjEPOJuxGMG8qJBQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", + "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", "dev": true, "dependencies": { - "@vitest/expect": "1.1.3", - "@vitest/runner": "1.1.3", - "@vitest/snapshot": "1.1.3", - "@vitest/spy": "1.1.3", - "@vitest/utils": "1.1.3", - "acorn-walk": "^8.3.1", - "cac": "^6.7.14", + "@vitest/expect": "1.3.1", + "@vitest/runner": "1.3.1", + "@vitest/snapshot": "1.3.1", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", + "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", "execa": "^8.0.1", @@ -11297,11 +11341,11 @@ "pathe": "^1.1.1", "picocolors": "^1.0.0", "std-env": "^3.5.0", - "strip-literal": "^1.3.0", + "strip-literal": "^2.0.0", "tinybench": "^2.5.1", - "tinypool": "^0.8.1", + "tinypool": "^0.8.2", "vite": "^5.0.0", - "vite-node": "1.1.3", + "vite-node": "1.3.1", "why-is-node-running": "^2.2.2" }, "bin": { @@ -11316,8 +11360,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "^1.0.0", - "@vitest/ui": "^1.0.0", + "@vitest/browser": "1.3.1", + "@vitest/ui": "1.3.1", "happy-dom": "*", "jsdom": "*" }, @@ -11694,6 +11738,175 @@ "node": ">=12" } }, + "node_modules/vitest/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz", + "integrity": "sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.1.tgz", + "integrity": "sha512-wlzcWiH2Ir7rdMELxFE5vuM7D6TsOcJ2Yw0c3vaBR3VOsJFVTx9xvwnAvhgU5Ii8Gd6+I11qNHwndDscIm0HXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.1.tgz", + "integrity": "sha512-YRXa1+aZIFN5BaImK+84B3uNK8C6+ynKLPgvn29X9s0LTVCByp54TB7tdSMHDR7GTV39bz1lOmlLDuedgTwwHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.1.tgz", + "integrity": "sha512-opjWJ4MevxeA8FhlngQWPBOvVWYNPFkq6/25rGgG+KOy0r8clYwL1CFd+PGwRqqMFVQ4/Qd3sQu5t7ucP7C/Uw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.1.tgz", + "integrity": "sha512-uBkwaI+gBUlIe+EfbNnY5xNyXuhZbDSx2nzzW8tRMjUmpScd6lCQYKY2V9BATHtv5Ef2OBq6SChEP8h+/cxifQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.1.tgz", + "integrity": "sha512-0bK9aG1kIg0Su7OcFTlexkVeNZ5IzEsnz1ept87a0TUgZ6HplSgkJAnFpEVRW7GRcikT4GlPV0pbtVedOaXHQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.1.tgz", + "integrity": "sha512-qB6AFRXuP8bdkBI4D7UPUbE7OQf7u5OL+R94JE42Z2Qjmyj74FtDdLGeriRyBDhm4rQSvqAGCGC01b8Fu2LthQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.1.tgz", + "integrity": "sha512-sHig3LaGlpNgDj5o8uPEoGs98RII8HpNIqFtAI8/pYABO8i0nb1QzT0JDoXF/pxzqO+FkxvwkHZo9k0NJYDedg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.1.tgz", + "integrity": "sha512-nD3YcUv6jBJbBNFvSbp0IV66+ba/1teuBcu+fBBPZ33sidxitc6ErhON3JNavaH8HlswhWMC3s5rgZpM4MtPqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.1.tgz", + "integrity": "sha512-7/XVZqgBby2qp/cO0TQ8uJK+9xnSdJ9ct6gSDdEr4MfABrjTyrW6Bau7HQ73a2a5tPB7hno49A0y1jhWGDN9OQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.1.tgz", + "integrity": "sha512-CYc64bnICG42UPL7TrhIwsJW4QcKkIt9gGlj21gq3VV0LL6XNb1yAdHVp1pIi9gkts9gGcT3OfUYHjGP7ETAiw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.1.tgz", + "integrity": "sha512-LN+vnlZ9g0qlHGlS920GR4zFCqAwbv2lULrR29yGaWP9u7wF5L7GqWu9Ah6/kFZPXPUkpdZwd//TNR+9XC9hvA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/vitest/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.1.tgz", + "integrity": "sha512-n+vkrSyphvmU0qkQ6QBNXCGr2mKjhP08mPRM/Xp5Ck2FV4NrHU+y6axzDeixUrCBHVUS51TZhjqrKBBsHLKb2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/vitest/node_modules/esbuild": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", @@ -11733,9 +11946,9 @@ } }, "node_modules/vitest/node_modules/rollup": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.10.0.tgz", - "integrity": "sha512-t2v9G2AKxcQ8yrG+WGxctBes1AomT0M4ND7jTFBCVPXQ/WFTvNSefIrNSmLKhIKBrvN8SG+CZslimJcT3W2u2g==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.1.tgz", + "integrity": "sha512-ggqQKvx/PsB0FaWXhIvVkSWh7a/PCLQAsMjBc+nA2M8Rv2/HG0X6zvixAB7KyZBRtifBUhy5k8voQX/mRnABPg==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -11748,26 +11961,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.10.0", - "@rollup/rollup-android-arm64": "4.10.0", - "@rollup/rollup-darwin-arm64": "4.10.0", - "@rollup/rollup-darwin-x64": "4.10.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.10.0", - "@rollup/rollup-linux-arm64-gnu": "4.10.0", - "@rollup/rollup-linux-arm64-musl": "4.10.0", - "@rollup/rollup-linux-riscv64-gnu": "4.10.0", - "@rollup/rollup-linux-x64-gnu": "4.10.0", - "@rollup/rollup-linux-x64-musl": "4.10.0", - "@rollup/rollup-win32-arm64-msvc": "4.10.0", - "@rollup/rollup-win32-ia32-msvc": "4.10.0", - "@rollup/rollup-win32-x64-msvc": "4.10.0", + "@rollup/rollup-android-arm-eabi": "4.12.1", + "@rollup/rollup-android-arm64": "4.12.1", + "@rollup/rollup-darwin-arm64": "4.12.1", + "@rollup/rollup-darwin-x64": "4.12.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.1", + "@rollup/rollup-linux-arm64-gnu": "4.12.1", + "@rollup/rollup-linux-arm64-musl": "4.12.1", + "@rollup/rollup-linux-riscv64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-musl": "4.12.1", + "@rollup/rollup-win32-arm64-msvc": "4.12.1", + "@rollup/rollup-win32-ia32-msvc": "4.12.1", + "@rollup/rollup-win32-x64-msvc": "4.12.1", "fsevents": "~2.3.2" } }, "node_modules/vitest/node_modules/vite": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.1.tgz", - "integrity": "sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz", + "integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==", "dev": true, "dependencies": { "esbuild": "^0.19.3", diff --git a/client-next/package.json b/client-next/package.json index ad3f1fa10a5..df70e5baf28 100644 --- a/client-next/package.json +++ b/client-next/package.json @@ -18,38 +18,38 @@ }, "dependencies": { "@googlemaps/polyline-codec": "1.0.28", - "bootstrap": "5.3.1", + "bootstrap": "5.3.3", "graphql": "16.8.1", "graphql-request": "6.1.0", - "maplibre-gl": "4.0.1", + "maplibre-gl": "4.1.0", "react": "18.2.0", - "react-bootstrap": "2.8.0", + "react-bootstrap": "2.10.1", "react-dom": "18.2.0", - "react-map-gl": "7.1.5" + "react-map-gl": "7.1.7" }, "devDependencies": { - "@graphql-codegen/cli": "5.0.0", - "@graphql-codegen/client-preset": "4.1.0", - "@graphql-codegen/introspection": "4.0.0", - "@parcel/watcher": "2.3.0", - "@testing-library/react": "14.1.2", - "@types/react": "18.2.21", - "@types/react-dom": "18.2.7", - "@typescript-eslint/eslint-plugin": "7.1.0", - "@typescript-eslint/parser": "7.1.0", - "@vitejs/plugin-react": "4.0.4", - "@vitest/coverage-v8": "1.1.3", - "eslint": "8.56.0", - "eslint-config-prettier": "9.0.0", - "eslint-plugin-import": "2.28.1", - "eslint-plugin-jsx-a11y": "6.7.1", - "eslint-plugin-react": "7.33.2", + "@graphql-codegen/cli": "5.0.2", + "@graphql-codegen/client-preset": "4.2.4", + "@graphql-codegen/introspection": "4.0.3", + "@parcel/watcher": "2.4.1", + "@testing-library/react": "14.2.1", + "@types/react": "18.2.65", + "@types/react-dom": "18.2.21", + "@typescript-eslint/eslint-plugin": "7.2.0", + "@typescript-eslint/parser": "7.2.0", + "@vitejs/plugin-react": "4.2.1", + "@vitest/coverage-v8": "1.3.1", + "eslint": "8.57.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsx-a11y": "6.8.0", + "eslint-plugin-react": "7.34.0", "eslint-plugin-react-hooks": "4.6.0", - "eslint-plugin-react-refresh": "0.4.3", + "eslint-plugin-react-refresh": "0.4.5", "jsdom": "24.0.0", - "prettier": "3.0.3", - "typescript": "5.2.2", + "prettier": "3.2.5", + "typescript": "5.4.2", "vite": "4.5.2", - "vitest": "1.1.3" + "vitest": "1.3.1" } } From 69377e4a9477356fd5dd494c0c0f9d5617c1060c Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Tue, 12 Mar 2024 14:26:01 +0000 Subject: [PATCH 70/83] Add changelog entry for #5731 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 9e2e515c463..5c5a9e6aa99 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -99,6 +99,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - 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) +- Fix world envelope builder when crossing Greenwich meridian [#5731](https://github.com/opentripplanner/OpenTripPlanner/pull/5731) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From b456b4474c47bc7597c94a6fe002e88d6eef578f Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Tue, 12 Mar 2024 18:24:28 +0000 Subject: [PATCH 71/83] Upgrade debug client to version 2024/03/2024-03-12T18:23 --- src/client/debug-client-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html index a7b15bef13b..84d1084320f 100644 --- a/src/client/debug-client-preview/index.html +++ b/src/client/debug-client-preview/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +

From 94512daf2fd931c112d50639acf3accc01a5542e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 01:08:35 +0000 Subject: [PATCH 72/83] chore(deps): update dependency io.github.git-commit-id:git-commit-id-maven-plugin to v8.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fb81075d4de..9a50e577ad8 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 - 8.0.0 + 8.0.1 From 800c758b4abaecc0992af56c83dcbbf4fbe95d92 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 01:08:43 +0000 Subject: [PATCH 73/83] chore(deps): update dependency org.apache.commons:commons-compress to v1.26.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9a50e577ad8..82567188005 100644 --- a/pom.xml +++ b/pom.xml @@ -930,7 +930,7 @@ org.apache.commons commons-compress - 1.26.0 + 1.26.1 test From ea159d544f6a8c3835b3826371e52a1dd87cbafc Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 11:06:49 +0100 Subject: [PATCH 74/83] Update actions version [ci skip] --- .github/workflows/cibuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index 28a84953af2..64f2fb8075f 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -75,7 +75,7 @@ jobs: # on windows there are frequent failures caused by page files being too small # https://github.com/actions/virtual-environments/issues/785 - name: Configure Windows Pagefile - uses: al-cheb/configure-pagefile-action@v1.3 + uses: al-cheb/configure-pagefile-action@v1.4 - name: Run tests run: mvn --batch-mode test -P prettierSkip From b57e52922552c1b651766be83290712b3250ee11 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 13:08:50 +0100 Subject: [PATCH 75/83] Update documentation for 2.5.0 release --- README.md | 2 +- doc-templates/Configuration.md | 4 +- docs/Basic-Tutorial.md | 16 ++++---- docs/Changelog.md | 69 +++++++++++++--------------------- docs/Configuration.md | 4 +- docs/Getting-OTP.md | 12 +++--- docs/RouterConfiguration.md | 2 +- docs/index.md | 3 +- 8 files changed, 49 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 4486818745b..953aa02b731 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ GTFS and OpenStreetMap). It applies real-time updates and alerts with immediate clients, finding itineraries that account for disruptions and service changes. Note that this branch contains **OpenTripPlanner 2**, the second major version of OTP, which has -been under development since 2018. The latest version of OTP is v2.4.0, released in September 2023. +been under development since 2018. The latest version of OTP is v2.5.0, released in March 2024. If you do not want to use this version, please switch to the final 1.x release tag `v1.5.0` or the `dev-1.x` branch. diff --git a/doc-templates/Configuration.md b/doc-templates/Configuration.md index 6344e270570..e06adc46dc5 100644 --- a/doc-templates/Configuration.md +++ b/doc-templates/Configuration.md @@ -146,7 +146,7 @@ text inserted is valid JSON (starts with `{` and ends with `}`). Variable substitution is performed on configuration file after the include file directive; Hence variable substitution is also performed on the text in the injected file. -Here is an example including variable substitution, assuming version 2.4.0 of OTP: +Here is an example including variable substitution, assuming version 2.5.0 of OTP: ```JSON // build-config.json @@ -170,7 +170,7 @@ The result will look like this: { "transitFeeds": [ { - "source": "netex-v2.4.0.obj" + "source": "netex-v2.5.0.obj" } ] } diff --git a/docs/Basic-Tutorial.md b/docs/Basic-Tutorial.md index 3d99d96f4da..a7a69b8a3bb 100644 --- a/docs/Basic-Tutorial.md +++ b/docs/Basic-Tutorial.md @@ -18,9 +18,9 @@ JAR containing all other libraries needed for OTP to work, and is available from repository. You will be able to go to [the OTP directory at Maven Central](https://repo1.maven.org/maven2/org/opentripplanner/otp/), navigate to -the [directory of releases](https://repo1.maven.org/maven2/org/opentripplanner/otp/2.4.0/), +the [directory of releases](https://repo1.maven.org/maven2/org/opentripplanner/otp/2.5.0/), and download -the [file with `shaded.jar` suffix](https://repo1.maven.org/maven2/org/opentripplanner/otp/2.4.0/otp-2.4.0-shaded.jar) +the [file with `shaded.jar` suffix](https://repo1.maven.org/maven2/org/opentripplanner/otp/2.5.0/otp-2.5.0-shaded.jar) . You may also want to get your own copy of the OTP source code @@ -129,7 +129,7 @@ below and in other tutorials. The simplest way to use OTP is to build a graph in a single step and start a server immediately, without saving it to disk. The command to do so is: - $ java -Xmx2G -jar otp-2.4.0-shaded.jar --build --serve /home/username/otp + $ java -Xmx2G -jar otp-2.5.0-shaded.jar --build --serve /home/username/otp where `/home/username/otp` should be the directory where you put your configuration and input files. @@ -154,13 +154,13 @@ build a graph from street and transit data then save it to a file using the `--b command line parameters together. If for example your current working directory (`.`) contains the input files and the OTP JAR file, you can use this command: - $ java -Xmx2G -jar otp-2.4.0-shaded.jar --build --save . + $ java -Xmx2G -jar otp-2.5.0-shaded.jar --build --save . This will produce a file called `graph.obj` in the same directory as the inputs. The server can then be started later using the `--load` parameter, and will read this file instead of building the graph from scratch: - $ java -Xmx2G -jar otp-2.4.0-shaded.jar --load . + $ java -Xmx2G -jar otp-2.5.0-shaded.jar --load . Another reason to perform these two phases separately is that the building process loads the entire GTFS and OSM data sets into memory, so can require significantly more memory than just running a @@ -177,16 +177,16 @@ graph once, and then layer transit data on top of the streets to make the final Again assuming the input files and OTP JAR file are in the current working directory, you can build a street graph with OSM and elevation data only (ignoring transit input files) with this command: - $ java -Xmx2G -jar otp-2.4.0-shaded.jar --buildStreet . + $ java -Xmx2G -jar otp-2.5.0-shaded.jar --buildStreet . Then, to build a graph layering transit data on top of the saved street graph (built using the previous command): - $ java -Xmx2G -jar otp-2.4.0-shaded.jar --loadStreet --save . + $ java -Xmx2G -jar otp-2.5.0-shaded.jar --loadStreet --save . Finally, the server can be started using the `--load` parameter: - $ java -Xmx2G -jar otp-2.4.0-shaded.jar --load . + $ java -Xmx2G -jar otp-2.5.0-shaded.jar --load . ## Command Line Switches diff --git a/docs/Changelog.md b/docs/Changelog.md index 5c5a9e6aa99..8ca70f59191 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -3,25 +3,39 @@ The changelog lists most feature changes between each release. The list is automatically created based on merged pull requests. Search GitHub issues and pull requests for smaller issues. -## 2.5.0 (under development) +## 2.6.0-SNAPSHOT (under development) + +[](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) + +## 2.5.0 (2024-03-13) + +### Notable Changes + +- Make GTFS GraphQL API an official API [#5339](https://github.com/opentripplanner/OpenTripPlanner/pull/5339) +- Make Transmodel GraphQl API an official API [#5573](https://github.com/opentripplanner/OpenTripPlanner/pull/5573), [#5637](https://github.com/opentripplanner/OpenTripPlanner/pull/5637) +- Deprecate REST API [#5580](https://github.com/opentripplanner/OpenTripPlanner/pull/5580) +- Transit group priority [#4999](https://github.com/opentripplanner/OpenTripPlanner/pull/4999), [#5583](https://github.com/opentripplanner/OpenTripPlanner/pull/5583), [#5638](https://github.com/opentripplanner/OpenTripPlanner/pull/5638) +- Transmodel GraphQL API for pass-through searches [#5320](https://github.com/opentripplanner/OpenTripPlanner/pull/5320) +- Migrate to Java 21 [#5421](https://github.com/opentripplanner/OpenTripPlanner/pull/5421) +- New debug client [#5334](https://github.com/opentripplanner/OpenTripPlanner/pull/5334) +- Update to latest GTFS Flex spec draft [#5564](https://github.com/opentripplanner/OpenTripPlanner/pull/5564), [#5655](https://github.com/opentripplanner/OpenTripPlanner/pull/5655) +- Restructure walk/bicycle/car preferences in router-config.json [#5582](https://github.com/opentripplanner/OpenTripPlanner/pull/5582) + +### Detailed changes by Pull Request - Gracefully handle nullable fields in TransitAlert [#5349](https://github.com/opentripplanner/OpenTripPlanner/pull/5349) - Remove transit with higher cost than best on-street itinerary filter [#5222](https://github.com/opentripplanner/OpenTripPlanner/pull/5222) -- Remove banDiscouragedCycling and banDiscouragedWalking [#5341](https://github.com/opentripplanner/OpenTripPlanner/pull/5341) +- Remove `banDiscouragedCycling` and `banDiscouragedWalking` [#5341](https://github.com/opentripplanner/OpenTripPlanner/pull/5341) - Fix rental scooter access [#5361](https://github.com/opentripplanner/OpenTripPlanner/pull/5361) - De-duplicate stops returned by `stopsByRadius` [#5366](https://github.com/opentripplanner/OpenTripPlanner/pull/5366) -- Fix value mapping for bikesAllowed in GTFS GraphQL API [#5368](https://github.com/opentripplanner/OpenTripPlanner/pull/5368) +- Fix value mapping for `bikesAllowed` in GTFS GraphQL API [#5368](https://github.com/opentripplanner/OpenTripPlanner/pull/5368) - Apply correct traversal permissions to barrier vertex [#5369](https://github.com/opentripplanner/OpenTripPlanner/pull/5369) -- Move GTFS GraphQL API out of the sandbox [#5339](https://github.com/opentripplanner/OpenTripPlanner/pull/5339) -- Transmodel GraphQL API for pass-through searches [#5320](https://github.com/opentripplanner/OpenTripPlanner/pull/5320) - Fix check for OSM relation members not being present in the extract [#5379](https://github.com/opentripplanner/OpenTripPlanner/pull/5379) - Add a configurable limit for the search window [#5293](https://github.com/opentripplanner/OpenTripPlanner/pull/5293) -- Fix fare calculation for combined interlined legs [#5408](https://github.com/opentripplanner/OpenTripPlanner/pull/5408) - Fix board slack list mapping in Transmodel API [#5420](https://github.com/opentripplanner/OpenTripPlanner/pull/5420) - Fix flexible quay querying in Transmodel API [#5417](https://github.com/opentripplanner/OpenTripPlanner/pull/5417) - Add validation for missing calls in SIRI update [#5403](https://github.com/opentripplanner/OpenTripPlanner/pull/5403) - Import Occupancy Status from GTFS-RT Vehicle Positions [#5372](https://github.com/opentripplanner/OpenTripPlanner/pull/5372) -- Add Roadmap epic template [#5413](https://github.com/opentripplanner/OpenTripPlanner/pull/5413) - Allow multiple zones in an unscheduled flex trip [#5376](https://github.com/opentripplanner/OpenTripPlanner/pull/5376) - Filter out null, empty and blank elements when mapping feed-scoped ids [#5428](https://github.com/opentripplanner/OpenTripPlanner/pull/5428) - Validate stop id in Transit leg reference [#5440](https://github.com/opentripplanner/OpenTripPlanner/pull/5440) @@ -30,77 +44,48 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Add stricter validation for flex areas [#5457](https://github.com/opentripplanner/OpenTripPlanner/pull/5457) - Remove HTTPS handling and its documentation [#5439](https://github.com/opentripplanner/OpenTripPlanner/pull/5439) - Add support for DSJ in transit leg reference [#5455](https://github.com/opentripplanner/OpenTripPlanner/pull/5455) -- Ignore negative travel-times in Raptor [#5443](https://github.com/opentripplanner/OpenTripPlanner/pull/5443) - Fix sort order bug in optimized transfers [#5446](https://github.com/opentripplanner/OpenTripPlanner/pull/5446) -- Siri file loader [#5460](https://github.com/opentripplanner/OpenTripPlanner/pull/5460) +- SIRI file loader [#5460](https://github.com/opentripplanner/OpenTripPlanner/pull/5460) - Calculate CO₂ emissions of itineraries [#5278](https://github.com/opentripplanner/OpenTripPlanner/pull/5278) -- Update NeTEx Java Model 2.0.15 [#5466](https://github.com/opentripplanner/OpenTripPlanner/pull/5466) -- Migrate to Java 21 [#5421](https://github.com/opentripplanner/OpenTripPlanner/pull/5421) -- Add Roadmap setup docs [#5468](https://github.com/opentripplanner/OpenTripPlanner/pull/5468) - Interpolate increasing stop times for GTFS-RT cancelled trips [#5348](https://github.com/opentripplanner/OpenTripPlanner/pull/5348) - Remove itineraries outside the search window in arriveBy search [#5433](https://github.com/opentripplanner/OpenTripPlanner/pull/5433) -- Add back walk-reluctance in Transmodel API [#5471](https://github.com/opentripplanner/OpenTripPlanner/pull/5471) -- Make `feedId` required for real-time updaters [#5502](https://github.com/opentripplanner/OpenTripPlanner/pull/5502) -- Fix serialization of `AtomicInteger` [#5508](https://github.com/opentripplanner/OpenTripPlanner/pull/5508) +- Add back walk reluctance in Transmodel API [#5471](https://github.com/opentripplanner/OpenTripPlanner/pull/5471) - Improve linking of fixed stops used by flex trips [#5503](https://github.com/opentripplanner/OpenTripPlanner/pull/5503) - Keep min transfer filter is not local to group-by-filters [#5436](https://github.com/opentripplanner/OpenTripPlanner/pull/5436) - Add paging deduplication when cropping [#5458](https://github.com/opentripplanner/OpenTripPlanner/pull/5458) -- Consolidate equivalent stops from several feeds [#5429](https://github.com/opentripplanner/OpenTripPlanner/pull/5429) - Check transport mode when mapping GroupStops [#5518](https://github.com/opentripplanner/OpenTripPlanner/pull/5518) -- Cleanup trip times - Part A [#5437](https://github.com/opentripplanner/OpenTripPlanner/pull/5437) - Transfer cost limit [#5516](https://github.com/opentripplanner/OpenTripPlanner/pull/5516) - Fix missed trip when arrive-by search-window is off by one minute [#5520](https://github.com/opentripplanner/OpenTripPlanner/pull/5520) -- Transit group priority - Part 1 [#4999](https://github.com/opentripplanner/OpenTripPlanner/pull/4999) - Remove `matchBusRoutesToStreets` [#5523](https://github.com/opentripplanner/OpenTripPlanner/pull/5523) -- Rename realtime to real-time in docs [#5535](https://github.com/opentripplanner/OpenTripPlanner/pull/5535) - Add same submode in alternative legs filter [#5548](https://github.com/opentripplanner/OpenTripPlanner/pull/5548) - Fix issue where stop points are sometimes added twice to index [#5552](https://github.com/opentripplanner/OpenTripPlanner/pull/5552) - Improve shutdown logic [#5514](https://github.com/opentripplanner/OpenTripPlanner/pull/5514) -- Create TripOnServiceDate for new siri realtime servicejourneys [#5542](https://github.com/opentripplanner/OpenTripPlanner/pull/5542) -- New debug client [#5334](https://github.com/opentripplanner/OpenTripPlanner/pull/5334) +- Create TripOnServiceDate for new SIRI real-time servicejourneys [#5542](https://github.com/opentripplanner/OpenTripPlanner/pull/5542) - Improve paging - avoid duplicates and missed itineraries when paging [#5551](https://github.com/opentripplanner/OpenTripPlanner/pull/5551) -- Create own parking preferences for bike and car in the internal model [#5521](https://github.com/opentripplanner/OpenTripPlanner/pull/5521) -- Make Transmodel GraphQl API an official OTP API [#5573](https://github.com/opentripplanner/OpenTripPlanner/pull/5573) - Add option to include stations in `nearest` search [#5390](https://github.com/opentripplanner/OpenTripPlanner/pull/5390) -- GTFS Flex spec update: separate columns for `location_id`, `location_group_id` [#5564](https://github.com/opentripplanner/OpenTripPlanner/pull/5564) -- Report NO_TRANSIT_CONNECTION when search-window is set. [#5570](https://github.com/opentripplanner/OpenTripPlanner/pull/5570) -- Transit priority - part 3 [#5583](https://github.com/opentripplanner/OpenTripPlanner/pull/5583) +- Report NO_TRANSIT_CONNECTION when search-window is set [#5570](https://github.com/opentripplanner/OpenTripPlanner/pull/5570) - Fix preference cost comparisons [#5586](https://github.com/opentripplanner/OpenTripPlanner/pull/5586) -- Report and throw away trip-times which fail sanity check [#5587](https://github.com/opentripplanner/OpenTripPlanner/pull/5587) - Consider escalator edges in island pruning [#5591](https://github.com/opentripplanner/OpenTripPlanner/pull/5591) -- Create own rental preferences for bike and car in the internal model [#5562](https://github.com/opentripplanner/OpenTripPlanner/pull/5562) - Adding situation-version to TransmodelGraphQL API [#5592](https://github.com/opentripplanner/OpenTripPlanner/pull/5592) -- Move REST API into sandbox [#5580](https://github.com/opentripplanner/OpenTripPlanner/pull/5580) - Fix high walk reluctance leading to zero egress results for rental searches [#5605](https://github.com/opentripplanner/OpenTripPlanner/pull/5605) - Remove GTFS-RT websocket updater [#5604](https://github.com/opentripplanner/OpenTripPlanner/pull/5604) -- Add stop layer to new Debug UI [#5602](https://github.com/opentripplanner/OpenTripPlanner/pull/5602) - Use fallback timezone if no transit data is loaded [#4652](https://github.com/opentripplanner/OpenTripPlanner/pull/4652) - Add new path for GTFS GraphQL API, remove batch feature [#5581](https://github.com/opentripplanner/OpenTripPlanner/pull/5581) -- Restructure walk/bicycle/car preferences in router-config.json [#5582](https://github.com/opentripplanner/OpenTripPlanner/pull/5582) -- Revert REST API spelling change of real-time [#5629](https://github.com/opentripplanner/OpenTripPlanner/pull/5629) - Remove `FareComponent` [#5613](https://github.com/opentripplanner/OpenTripPlanner/pull/5613) -- Add AreaStop layer to new debug frontend [#5636](https://github.com/opentripplanner/OpenTripPlanner/pull/5636) -- Allow configuration of vector tiles base path [#5627](https://github.com/opentripplanner/OpenTripPlanner/pull/5627) -- Change Transmodel API path to `/otp/transmodel/v3` [#5637](https://github.com/opentripplanner/OpenTripPlanner/pull/5637) - Add flexibleArea to GroupStop Quays [#5625](https://github.com/opentripplanner/OpenTripPlanner/pull/5625) -- Pass-through should override transit-group-priority [#5638](https://github.com/opentripplanner/OpenTripPlanner/pull/5638) -- Introduce `generalizedCostPlusPenalty` to make cost comparsion fairer [#5483](https://github.com/opentripplanner/OpenTripPlanner/pull/5483) +- Introduce `generalizedCostPlusPenalty` to make cost comparison fairer [#5483](https://github.com/opentripplanner/OpenTripPlanner/pull/5483) - Separate walk time from non-transit time [#5648](https://github.com/opentripplanner/OpenTripPlanner/pull/5648) - Remove "fare" [#5645](https://github.com/opentripplanner/OpenTripPlanner/pull/5645) -- Refactor GroupStopBuilder addLocation method [#5651](https://github.com/opentripplanner/OpenTripPlanner/pull/5651) - Remove `VehicleToStopHeuristics` [#5381](https://github.com/opentripplanner/OpenTripPlanner/pull/5381) - Set defaults of the modes WALK, even if one and not the others are set [#5675](https://github.com/opentripplanner/OpenTripPlanner/pull/5675) - Reduce flex default access/egress penalty [#5674](https://github.com/opentripplanner/OpenTripPlanner/pull/5674) -- Add scooter preferences [#5632](https://github.com/opentripplanner/OpenTripPlanner/pull/5632) -- Add GroupStop layer to new debug frontend [#5666](https://github.com/opentripplanner/OpenTripPlanner/pull/5666) -- Update to newest version of GTFS Flex location groups [#5655](https://github.com/opentripplanner/OpenTripPlanner/pull/5655) +- Add scooter preferences [#5632](https://github.com/opentripplanner/OpenTripPlanner/pull/5632) - 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) - Fix time penalty [#5715](https://github.com/opentripplanner/OpenTripPlanner/pull/5715) - Fix world envelope builder when crossing Greenwich meridian [#5731](https://github.com/opentripplanner/OpenTripPlanner/pull/5731) -[](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) diff --git a/docs/Configuration.md b/docs/Configuration.md index 93ca1fa6c1e..ed58f13fa6e 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -173,7 +173,7 @@ text inserted is valid JSON (starts with `{` and ends with `}`). Variable substitution is performed on configuration file after the include file directive; Hence variable substitution is also performed on the text in the injected file. -Here is an example including variable substitution, assuming version 2.4.0 of OTP: +Here is an example including variable substitution, assuming version 2.5.0 of OTP: ```JSON // build-config.json @@ -197,7 +197,7 @@ The result will look like this: { "transitFeeds": [ { - "source": "netex-v2.4.0.obj" + "source": "netex-v2.5.0.obj" } ] } diff --git a/docs/Getting-OTP.md b/docs/Getting-OTP.md index 1186209854b..a71bc02b5d8 100644 --- a/docs/Getting-OTP.md +++ b/docs/Getting-OTP.md @@ -9,8 +9,8 @@ the [release pages on GitHub](https://github.com/opentripplanner/OpenTripPlanner or [the OTP directory at Maven Central](https://repo1.maven.org/maven2/org/opentripplanner/otp/), navigate to the highest version number, and download the file whose name ends with `shaded.jar`. -Note that version numbers like `v2.1.0-rc1` or `v2.4.0-SNAPSHOT` refer to development builds _ -before_ the release version `v2.4.0`. The existence of a build `vX.Y.Z-SNAPSHOT` does not mean +Note that version numbers like `v2.1.0-rc1` or `v2.5.0-SNAPSHOT` refer to development builds _ +before_ the release version `v2.5.0`. The existence of a build `vX.Y.Z-SNAPSHOT` does not mean that `vX.Y.Z` has been released yet. We use the [Github Actions CI system](https://github.com/opentripplanner/OpenTripPlanner/actions) to @@ -87,7 +87,7 @@ For example, you could do the following: ```bash cd OpenTripPlanner -git checkout v2.4.0 +git checkout v2.5.0 git clean -df mvn clean package -DskipTests ``` @@ -110,8 +110,8 @@ file) to the Maven repository, from which it can be automatically included in ot This repository is machine-readable (by Maven or other build systems) and also provides human readable directory listings via HTTP. You can fetch an OTP JAR from this repository by constructing -the proper URL for the release you want. For example, release 2.4.0 will be found -at `https://repo1.maven.org/maven2/org/opentripplanner/otp/2.4.0/otp-2.4.0-shaded.jar`. +the proper URL for the release you want. For example, release 2.5.0 will be found +at `https://repo1.maven.org/maven2/org/opentripplanner/otp/2.5.0/otp-2.5.0-shaded.jar`. To make use of OTP in another Maven project, you must specify it as a dependency in that project's `pom.xml`: @@ -120,6 +120,6 @@ project's `pom.xml`: org.opentripplanner otp - 2.4.0 + 2.5.0 ``` diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index 503b8c7370f..30d7c414bfd 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -438,7 +438,7 @@ Used to group requests when monitoring OTP. ```JSON // router-config.json { - "configVersion" : "v2.4.0-EN000121", + "configVersion" : "v2.5.0-EN000121", "server" : { "apiProcessingTimeout" : "7s", "traceParameters" : [ diff --git a/docs/index.md b/docs/index.md index b70c99e4d52..f1ddc791212 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,7 +26,8 @@ the selector in the upper left of the published documentation. **Releases** -- [Latest](http://docs.opentripplanner.org/en/latest) - Version 2.4.0 (the git master branch) +- [Latest](http://docs.opentripplanner.org/en/latest) - Version 2.5 (the git master branch) +- [v2.4.0](http://docs.opentripplanner.org/en/v2.4.0) - Version 2.4 - [v2.3.0](http://docs.opentripplanner.org/en/v2.3.0) - Version 2.3 - [v2.2.0](http://docs.opentripplanner.org/en/v2.2.0) - Version 2.2 - [v2.1.0](http://docs.opentripplanner.org/en/v2.1.0) - Version 2.1 From 6596982b8a8e4bf959b76590bfc681e257158d31 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 13:09:35 +0100 Subject: [PATCH 76/83] Update MASTER_BRANCH_VERSION --- .github/workflows/cibuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index 64f2fb8075f..5a48da6bc44 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -87,7 +87,7 @@ jobs: LOCAL_BRANCH: local-pages REMOTE_BRANCH: main TOKEN: ${{ secrets.CHANGELOG_TOKEN }} - MASTER_BRANCH_VERSION: 2.4.0 + MASTER_BRANCH_VERSION: 2.5.0 steps: From fc4a4292b2385560208ba5a3a25e515983e57573 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 13:18:58 +0100 Subject: [PATCH 77/83] Fix documentation output --- docs/RouterConfiguration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index 30d7c414bfd..503b8c7370f 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -438,7 +438,7 @@ Used to group requests when monitoring OTP. ```JSON // router-config.json { - "configVersion" : "v2.5.0-EN000121", + "configVersion" : "v2.4.0-EN000121", "server" : { "apiProcessingTimeout" : "7s", "traceParameters" : [ From b301ea7c70f2ce7bb22c7f8e7fba6f8654cea3a5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 13:24:41 +0100 Subject: [PATCH 78/83] Prepare release 2.5.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 82567188005..865bd206900 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ https://opentripplanner.org org.opentripplanner otp - 2.5.0-SNAPSHOT + 2.5.0 jar From e7872c17845dbeb98110048c193c4dc777abf971 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 13:43:43 +0100 Subject: [PATCH 79/83] Switch order of release tasks --- docs/ReleaseChecklist.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/ReleaseChecklist.md b/docs/ReleaseChecklist.md index 7702a60e51c..c74f0662964 100644 --- a/docs/ReleaseChecklist.md +++ b/docs/ReleaseChecklist.md @@ -69,12 +69,6 @@ manually is more tedious, but keeps eyes on each step and is less prone to failu * Apply the changes recorded in https://github.com/opentripplanner/OpenTripPlanner/tree/signed-deploy-to-central * While still on the tag commit, run `mvn deploy -Prelease`. -* Set up next development iteration - * Add a new section header to `docs/Changelog.md` like `x.y+1.0-SNAPSHOT (in progress)` - * Edit minor version in `pom.xml` to `x.y+1.0-SNAPSHOT` - * `git add pom.xml docs/Changelog.md` - * `git commit -m "Prepare next development iteration x.y+1.0-SNAPSHOT"` - * `git push` * Check that Maven artifact appears on Maven Central * [Directory listing of OTP releases on Maven Central](https://repo1.maven.org/maven2/org/opentripplanner/otp/) * It may take a while (half an hour) for releases to show up in the central repo after Travis @@ -83,6 +77,12 @@ manually is more tedious, but keeps eyes on each step and is less prone to failu * `git checkout dev-2.x` * `git merge master` * `git push` +* Set up next development iteration + * Add a new section header to `docs/Changelog.md` like `x.y+1.0-SNAPSHOT (in progress)` + * Edit minor version in `pom.xml` to `x.y+1.0-SNAPSHOT` + * `git add pom.xml docs/Changelog.md` + * `git commit -m "Prepare next development iteration x.y+1.0-SNAPSHOT"` + * `git push` * Email the OTP dev and users mailing lists * Mention the new version number. * Provide links to the new developer documentation. From 3796cfd32cc57b2820bd6acd618ebd7063c806ec Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 13:44:35 +0100 Subject: [PATCH 80/83] Prepare next development iteration 2.6.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 865bd206900..4197a9c20aa 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ https://opentripplanner.org org.opentripplanner otp - 2.5.0 + 2.6.0-SNAPSHOT jar From 8c78db1c2f6798d0334443ed99c211c9585b5d6f Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 13:46:04 +0100 Subject: [PATCH 81/83] Update release checklist [ci skip] --- docs/ReleaseChecklist.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ReleaseChecklist.md b/docs/ReleaseChecklist.md index c74f0662964..0f7c0667762 100644 --- a/docs/ReleaseChecklist.md +++ b/docs/ReleaseChecklist.md @@ -83,7 +83,7 @@ manually is more tedious, but keeps eyes on each step and is less prone to failu * `git add pom.xml docs/Changelog.md` * `git commit -m "Prepare next development iteration x.y+1.0-SNAPSHOT"` * `git push` -* Email the OTP dev and users mailing lists +* Send a message in Gitter and email the OTP users mailing lists * Mention the new version number. * Provide links to the new developer documentation. * Provide links to the artifacts directory on Maven Central. From 17a36915ef205e804b129cbde5ef5c55dcad744d Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Wed, 13 Mar 2024 12:57:47 +0000 Subject: [PATCH 82/83] Add changelog entry for #5660 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 8ca70f59191..cfe8cde5133 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -5,6 +5,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle ## 2.6.0-SNAPSHOT (under development) +- ISO-8601 date time for GTFS API itinerary responses [#5660](https://github.com/opentripplanner/OpenTripPlanner/pull/5660) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From 60aeb8cddcbce0f73cd517d2b3c2d6158965cc55 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 14:13:01 +0100 Subject: [PATCH 83/83] Remove extra quote [ci skip] --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 655a1908a87..c1189f21ba1 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1622,7 +1622,7 @@ type Money { amount: Float! } -"""" +""" An ISO-8601-formatted duration, i.e. `PT2H30M` for 2 hours and 30 minutes. Negative durations are formatted like `-PT10M`.