Siri: cheapest [fuel] near me intent + App Shortcuts (cached-first, freshness label)

This commit is contained in:
FuelBoard Contributor
2026-08-14 12:32:31 +01:00
parent b5fe21c44b
commit 29d4a0472b
4 changed files with 294 additions and 0 deletions
@@ -0,0 +1 @@
../../../Shared/SiriCheapestLookup.swift
@@ -406,3 +406,73 @@ final class DistanceLabelTests: XCTestCase {
XCTAssertEqual(DistanceUnit.kilometers.displayMiles(15), 24) // 15 mi = 24.1 km
}
}
final class SiriCheapestLookupTests: XCTestCase {
private func station(_ id: String, lat: Double, lng: Double, _ prices: [FuelType: Double]) -> FuelStation {
FuelStation(id: id, name: id, brand: "X", address: "", postcode: "", lat: lat, lng: lng, prices: prices, priceUpdated: nil)
}
func testCheapestPicksLowestPriceNotNearest() {
// Near station is pricier; far station is cheaper price must win.
let stations = [
station("near", lat: 53.0, lng: -1.0, [.e10: 145.9]),
station("far", lat: 53.5, lng: -1.5, [.e10: 139.9]),
]
let result = SiriCheapestLookup.cheapest(in: stations, fuel: .e10, fromLat: 53.01, lng: -1.01)
XCTAssertEqual(result?.id, "far", "cheapest by price, not by distance")
}
func testCheapestTieBreaksByDistance() {
let stations = [
station("near", lat: 53.0, lng: -1.0, [.e10: 140.0]),
station("far", lat: 53.9, lng: -1.9, [.e10: 140.0]),
]
let result = SiriCheapestLookup.cheapest(in: stations, fuel: .e10, fromLat: 53.01, lng: -1.01)
XCTAssertEqual(result?.id, "near", "equal prices resolve to the nearest station")
}
func testCheapestSkipsStationsWithoutThatFuel() {
let stations = [
station("noDiesel", lat: 53.0, lng: -1.0, [.e10: 139.9]),
station("sellsDiesel", lat: 53.5, lng: -1.5, [.diesel: 149.9]),
]
let result = SiriCheapestLookup.cheapest(in: stations, fuel: .diesel, fromLat: 53.01, lng: -1.01)
XCTAssertEqual(result?.id, "sellsDiesel", "stations without the fuel are skipped")
}
func testCheapestReturnsNilWhenNoStationSellsFuel() {
let stations = [station("a", lat: 53.0, lng: -1.0, [.e10: 139.9])]
XCTAssertNil(SiriCheapestLookup.cheapest(in: stations, fuel: .diesel, fromLat: 53.0, lng: -1.0))
}
func testCheapestReturnsNilForEmptyInput() {
XCTAssertNil(SiriCheapestLookup.cheapest(in: [], fuel: .e10, fromLat: 53.0, lng: -1.0))
}
func testFreshnessLabelUsesDataUpdatedStamp() {
let label = SiriCheapestLookup.freshnessLabel(
updated: "2026-08-14T10:31:36.000Z",
lastRefresh: nil
)
XCTAssertTrue(label.hasPrefix("as of "), "stamp must be prefixed for the dialog")
XCTAssertFalse(label.contains("10:31"), "stamp is converted to the user's local time, not raw UTC")
}
func testFreshnessLabelFallsBackToLastRefresh() {
let label = SiriCheapestLookup.freshnessLabel(updated: nil, lastRefresh: Date(timeIntervalSince1970: 0))
XCTAssertTrue(label.hasPrefix("as of "), "local refresh date is used when no GOV.UK stamp exists")
}
func testFreshnessLabelEmptyWithoutAnyDate() {
XCTAssertEqual(SiriCheapestLookup.freshnessLabel(updated: nil, lastRefresh: nil), "")
}
func testFreshnessLabelToleratesPlainISODate() {
// Some relays emit no fractional seconds.
let label = SiriCheapestLookup.freshnessLabel(
updated: "2026-08-14T10:31:36Z",
lastRefresh: nil
)
XCTAssertTrue(label.hasPrefix("as of "), "plain ISO 8601 still parses")
}
}