Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
package org.opentripplanner.assertions;

import java.util.List;
import org.opentripplanner.client.model.TripPlan;

public class ItineraryAssertionError extends AssertionError {

private final List<ItineraryMatchResult> failedResults;
private final List<List<String>> expectedLegs;
private final boolean strictTransitMatching;
private final TripPlan tripPlan;

public ItineraryAssertionError(String message, List<ItineraryMatchResult> failedResults) {
/** Captures reportable expectations without exposing executable predicates. */
public ItineraryAssertionError(
String message,
List<ItineraryMatchResult> failedResults,
List<List<String>> expectedLegs,
boolean strictTransitMatching,
TripPlan tripPlan) {
super(message);
this.failedResults = failedResults;
this.failedResults = List.copyOf(failedResults);
this.expectedLegs = expectedLegs.stream().map(List::copyOf).toList();
this.strictTransitMatching = strictTransitMatching;
this.tripPlan = tripPlan;
}

public List<ItineraryMatchResult> getFailedResults() {
return failedResults;
}

public List<List<String>> getExpectedLegs() {
return expectedLegs;
}

public boolean isStrictTransitMatching() {
return strictTransitMatching;
}

/** The response used by the failed assertion, or null for the legacy constructor. */
public TripPlan getTripPlan() {
return tripPlan;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public ItineraryAssertions withRouteShortName(String... shortNames) {

public ItineraryAssertions withFarePrice(float price, String riderCategoryId, String mediumId) {
addCurrentLegCriterion(
"fare $%.2f".formatted(price),
"fare %.2f (rider category %s, medium %s)".formatted(price, riderCategoryId, mediumId),
leg ->
leg.fareProducts().stream()
.filter(fp -> fp.product().riderCategory().isPresent())
Expand Down Expand Up @@ -154,7 +154,14 @@ public void assertMatches(TripPlan tripPlan) {
}

String fullError = header + criteriaSection + failuresSection;
throw new ItineraryAssertionError(fullError, failedResults);
throw new ItineraryAssertionError(
fullError,
failedResults,
distinctLegCriteria.stream()
.map(criteria -> criteria.stream().map(LegCriterion::message).toList())
.toList(),
strictTransitMatching,
tripPlan);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,8 @@ void partialMatchesAndErrorDetailsAreIncluded() {
}

@Test
void withFarePriceHandlesPositiveAndNegativeMatches() {
List<FareProductUse> fares =
List.of(fare("orca:regular", "orca:cash"), fare(2.75f, "orca:regular", "orca:cash"));
void withFarePriceMatchesFareWithSpecifiedPriceRiderCategoryAndMedium() {
List<FareProductUse> fares = List.of(fare(2.75f, "orca:regular", "orca:cash"));
TripPlan plan =
tripPlan(itinerary(transitLeg("E", "E Line", LegMode.BUS, Duration.ofMinutes(12), fares)));

Expand All @@ -143,6 +142,13 @@ void withFarePriceHandlesPositiveAndNegativeMatches() {
.withRouteShortName("E")
.withFarePrice(2.75f, "orca:regular", "orca:cash")
.assertMatches(plan));
}

@Test
void withFarePriceReportsMismatchedFare() {
List<FareProductUse> fares = List.of(fare(2.75f, "orca:regular", "orca:cash"));
TripPlan plan =
tripPlan(itinerary(transitLeg("E", "E Line", LegMode.BUS, Duration.ofMinutes(12), fares)));

ItineraryAssertionError error =
assertThrows(
Expand All @@ -153,17 +159,15 @@ void withFarePriceHandlesPositiveAndNegativeMatches() {
.withRouteShortName("E")
.withFarePrice(3.00f, "orca:regular", "orca:cash")
.assertMatches(plan));
assertThat(error.getMessage()).contains("fare $3.00");
}

@Test
void deprecatedAliasExtendsCanonicalError() {
List<ItineraryMatchResult> failedResults = List.of(ItineraryMatchResult.success(List.of()));

ItineraryAssertionError error = new ItineraryAssertionError("boom", failedResults);

assertThat(error).isInstanceOf(ItineraryAssertionError.class);
assertThat(error.getFailedResults()).isEqualTo(failedResults);
String expectedFareCriterion = "fare 3.00 (rider category orca:regular, medium orca:cash)";
assertThat(error.getExpectedLegs())
.containsExactly(List.of("route '[E]'", expectedFareCriterion));
assertThat(error.getFailedResults()).hasSize(1);
assertThat(error.getFailedResults().get(0).getPartialMatches()).hasSize(1);
LegMatchingState partialMatch = error.getFailedResults().get(0).getPartialMatches().get(0);
assertThat(partialMatch.getMatchingCriteria()).isEqualTo("route '[E]'");
assertThat(partialMatch.getMissingCriteria()).isEqualTo(expectedFareCriterion);
}

private static TripPlan tripPlan(Itinerary... itineraries) {
Expand Down