Siri: cheapest [fuel] near me intent + App Shortcuts (cached-first, freshness label)
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user