XcodeGen project (Notes / NotesMac / NotesTests), Swift 6 strict concurrency, iCloud-document storage via IndieSync with a SwiftData cache, automatic capture context (location, place, time zone, device) on every note, context-based relevance ranking with a 'Right here, right now' shelf, tags, search, and the square.and.pencil-on-red app icon.
69 lines
2.8 KiB
Swift
69 lines
2.8 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import Notes
|
|
|
|
struct RelevanceTests {
|
|
private let coffeeShop = (lat: 37.8044, lon: -122.2712) // Oakland
|
|
private let farAway = (lat: 40.7128, lon: -74.0060) // NYC
|
|
|
|
private func signals(
|
|
lat: Double? = nil,
|
|
lon: Double? = nil,
|
|
place: String? = nil,
|
|
createdAt: Date = Date(timeIntervalSinceNow: -7 * 86_400)
|
|
) -> RelevanceSignals {
|
|
RelevanceSignals(
|
|
latitude: lat, longitude: lon, placeName: place, locality: nil,
|
|
createdAt: createdAt, timeZoneID: TimeZone.current.identifier
|
|
)
|
|
}
|
|
|
|
@Test func nearbyNoteOutscoresFarNote() {
|
|
let query = RelevanceQuery(latitude: coffeeShop.lat, longitude: coffeeShop.lon)
|
|
let near = Relevance.score(signals(lat: coffeeShop.lat, lon: coffeeShop.lon), query: query)
|
|
let far = Relevance.score(signals(lat: farAway.lat, lon: farAway.lon), query: query)
|
|
#expect(near > far)
|
|
#expect(near >= Relevance.surfacingThreshold)
|
|
}
|
|
|
|
@Test func farOldNoteStaysBelowThreshold() {
|
|
let query = RelevanceQuery(latitude: coffeeShop.lat, longitude: coffeeShop.lon)
|
|
let score = Relevance.score(
|
|
signals(lat: farAway.lat, lon: farAway.lon, createdAt: Date(timeIntervalSinceNow: -180 * 86_400)),
|
|
query: query
|
|
)
|
|
#expect(score < Relevance.surfacingThreshold)
|
|
}
|
|
|
|
@Test func samePlaceNameBoostsWithoutCoordinates() {
|
|
var query = RelevanceQuery()
|
|
query.placeName = "Blue Bottle Coffee"
|
|
let matching = Relevance.score(signals(place: "blue bottle coffee"), query: query)
|
|
let other = Relevance.score(signals(place: "Some Other Bar"), query: query)
|
|
#expect(matching > other)
|
|
}
|
|
|
|
@Test func sameHourOutscoresOppositeHour() {
|
|
let calendar = Calendar.current
|
|
let now = Date()
|
|
let sameHourYesterday = calendar.date(byAdding: .day, value: -1, to: now)!
|
|
let twelveHoursOff = calendar.date(byAdding: .hour, value: -12, to: sameHourYesterday)!
|
|
var query = RelevanceQuery()
|
|
query.date = now
|
|
let same = Relevance.score(signals(createdAt: sameHourYesterday), query: query)
|
|
let opposite = Relevance.score(signals(createdAt: twelveHoursOff), query: query)
|
|
#expect(same > opposite)
|
|
}
|
|
|
|
@Test func fresherNoteScoresHigher() {
|
|
let query = RelevanceQuery()
|
|
// Same clock time on different days isolates the recency term.
|
|
let calendar = Calendar.current
|
|
let recent = calendar.date(byAdding: .day, value: -7, to: query.date)!
|
|
let old = calendar.date(byAdding: .day, value: -98, to: query.date)!
|
|
let fresh = Relevance.score(signals(createdAt: recent), query: query)
|
|
let stale = Relevance.score(signals(createdAt: old), query: query)
|
|
#expect(fresh > stale)
|
|
}
|
|
}
|