Worth the Drive: calculation audit + listing/detail polish
Calculation audit (brief config: 30 MPG imperial, £60 fill-up, baseline
Rontec Shelf 171.9p at 0.4 mi):
- One mile<->kilometre constant pair (kilometresPerMile 1.609344,
metresPerMile 1609.344) replaces the mixed 1609.34 / 0.621371 / 1.60934
used in the savings path. Effect ~2 ppm (invisible), but the conversions
are now auditable in one place.
- New FuelSavingsCalculationAuditTests (20 deterministic tests, no live
MKDirections) pins the brief's three stations - Tesco 170.9p/2.0 mi,
MFG Hare & Hounds 172.9p/2.8 mi, PGG Napoleon 171.9p/2.8 mi - plus
imperial-vs-US gallon, MPG and budget scaling, the break-even tolerance
boundary, the nearer-candidate clamp, route-unavailable, mixed-basis
estimates and display-rounding boundaries.
- Formula unchanged, and verified correct: fixed quantity (budget / baseline
price), pump saving, round-trip extra distance clamped at zero, travel fuel
priced at the candidate station, +/-5p break even, baseline labelled
"Closest station", sorting on the unrounded net saving. The brief's "£0.18"
for Tesco is the rounded 1 dp extra-distance caption (2.02-2.05 mi reads as
"2.0 mi"), not a rounding bug in the money.
UI (uncommitted since d7a0ecb):
- Done bar drawn in the bottom safe area from keyboard notifications:
.toolbar(placement: .keyboard) is device-dependent (present on the 15 Pro,
absent on the SE on the same iOS build).
- Favourite star in the More-info heading, wired to the same fuel-scoped
toggle as the listing rows at all three call sites.
- CHEAPEST/TOP badge moved above the price so it reads as part of it.
- Listing rows carry the real session fill-up amount instead of a hard zero
(the compact banner does not print it today; a future row layout would).
153 tests, 0 failures. Simulator and device builds succeed.
This commit is contained in:
@@ -374,4 +374,62 @@ final class FuelSavingsEstimateTests: XCTestCase {
|
||||
"net saving decides the order, not the pump price")
|
||||
XCTAssertEqual(ranked.last?.id, "cheap-but-far")
|
||||
}
|
||||
|
||||
// MARK: Row copy
|
||||
|
||||
/// The row's extra-driving caption must follow the DISPLAY unit: the stored
|
||||
/// figure is always miles, and converting by the current unit instead would
|
||||
/// leave a km user's figure unlabelled and 1.6× too large.
|
||||
func testExtraTravelLabelFollowsTheDisplayUnit() {
|
||||
XCTAssertEqual(
|
||||
FuelSavingsFormat.extraTravelLabel(extraDistanceMiles: 19.9, unit: .miles),
|
||||
"19.9 mi more driving than closest"
|
||||
)
|
||||
XCTAssertEqual(
|
||||
FuelSavingsFormat.extraTravelLabel(extraDistanceMiles: 19.9, unit: .kilometers),
|
||||
"32.0 km more driving than closest"
|
||||
)
|
||||
XCTAssertNil(FuelSavingsFormat.extraTravelLabel(extraDistanceMiles: 0, unit: .miles),
|
||||
"the baseline row has no extra travel to report")
|
||||
// The same conversion backs the detail sheet's extra-distance figure,
|
||||
// which used to be hardcoded miles ("%.1f miles") for km users too.
|
||||
XCTAssertEqual(FuelSavingsFormat.distance(19.9, unit: .miles), "19.9 mi")
|
||||
XCTAssertEqual(FuelSavingsFormat.distance(19.9, unit: .kilometers), "32.0 km")
|
||||
}
|
||||
|
||||
/// The baseline capsule has to say what it IS: it previously repeated the
|
||||
/// status word above it ("Closest station" twice) and never explained that
|
||||
/// the savings are measured against it.
|
||||
func testCapsuleHeadlineMarksTheBaselineAndKeepsTheEstimateMarker() {
|
||||
let baseline = FuelSavingsResult(
|
||||
fillLitres: 30,
|
||||
grossSavingGBP: 0,
|
||||
extraDrivingCostGBP: 0,
|
||||
extraDistanceMiles: 0,
|
||||
netSavingGBP: 0,
|
||||
status: .baseline
|
||||
)
|
||||
XCTAssertEqual(baseline.capsuleHeadline(), "Closest station · your baseline")
|
||||
|
||||
let saving = FuelSavingsResult(
|
||||
fillLitres: 30,
|
||||
grossSavingGBP: 2.40,
|
||||
extraDrivingCostGBP: 1.40,
|
||||
extraDistanceMiles: 5.2,
|
||||
netSavingGBP: 1.00,
|
||||
status: .worthTheDrive,
|
||||
distanceBasis: .straightLine
|
||||
)
|
||||
XCTAssertEqual(saving.capsuleHeadline(), "Save £1.00 after travel (est.)")
|
||||
|
||||
let worse = FuelSavingsResult(
|
||||
fillLitres: 30,
|
||||
grossSavingGBP: 1.40,
|
||||
extraDrivingCostGBP: 1.70,
|
||||
extraDistanceMiles: 6.7,
|
||||
netSavingGBP: -0.31,
|
||||
status: .notWorthTheDrive
|
||||
)
|
||||
XCTAssertEqual(worse.capsuleHeadline(), "£0.31 worse off after travel")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user