Files
conjure/Tests/ConjureKitTests/LaunchHistoryTests.swift
T

141 lines
6.7 KiB
Swift

import ConjureKit
import Foundation
import Testing
@Test @MainActor
func suggestionsPreferFrequencyThenRecencyAndKeepUnusedAppsAlphabetical() {
let suite = "ConjureHistoryTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defer { defaults.removePersistentDomain(forName: suite) }
var instant = Date(timeIntervalSinceReferenceDate: 1_000)
let history = LaunchHistory(defaults: defaults, now: { instant })
let apps = ["Unused Zebra", "Recent", "Frequent", "Unused Alpha", "Older"].map(historyApplication)
#expect(history.suggestions(in: apps).map(\.name) == [
"Frequent", "Older", "Recent", "Unused Alpha", "Unused Zebra",
])
history.recordLaunch(of: apps[4])
instant += 10
history.recordLaunch(of: apps[2])
history.recordLaunch(of: apps[2])
instant += 10
history.recordLaunch(of: apps[1])
#expect(history.suggestions(in: apps).map(\.name) == [
"Frequent", "Recent", "Older", "Unused Alpha", "Unused Zebra",
])
}
@Test @MainActor
func suggestionsRetainUsageAcrossHistoryInstancesAndDoNotReintroduceMissingApps() {
let suite = "ConjureHistoryTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defer { defaults.removePersistentDomain(forName: suite) }
let instant = Date(timeIntervalSinceReferenceDate: 2_000)
let alpha = historyApplication("Alpha")
let zebra = historyApplication("Zebra")
let removed = historyApplication("Removed")
let history = LaunchHistory(defaults: defaults, now: { instant })
history.recordLaunch(of: zebra)
history.recordLaunch(of: removed)
history.recordLaunch(of: removed)
let reloaded = LaunchHistory(defaults: UserDefaults(suiteName: suite)!, now: { instant })
#expect(reloaded.suggestions(in: [alpha, zebra]).map(\.name) == ["Zebra", "Alpha"])
reloaded.recordLaunch(of: alpha)
#expect(reloaded.suggestions(in: [zebra, alpha]).map(\.name) == ["Alpha", "Zebra"])
}
@Test @MainActor
func usageTracksApplicationIdentityRatherThanDisplayNameAndKeepsTiesDeterministic() {
let suite = "ConjureHistoryTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defer { defaults.removePersistentDomain(forName: suite) }
let instant = Date(timeIntervalSinceReferenceDate: 3_000)
let history = LaunchHistory(defaults: defaults, now: { instant })
let first = Application(url: URL(fileURLWithPath: "/First/Editor.app"), name: "Editor")
let second = Application(url: URL(fileURLWithPath: "/Second/Editor.app"), name: "Editor")
#expect(history.suggestions(in: [second, first]).map(\.url) == [first.url, second.url])
history.recordLaunch(of: second)
#expect(history.suggestions(in: [first, second]).map(\.url) == [second.url, first.url])
let renamed = Application(url: second.url, name: "Renamed Editor")
#expect(history.suggestions(in: [first, renamed]).map(\.url) == [second.url, first.url])
history.recordLaunch(of: first)
#expect(history.suggestions(in: [second, first]).map(\.url) == [first.url, second.url])
}
@Test @MainActor
func applicationIdentityIgnoresDirectoryURLFormattingInLaunchHistory() {
let suite = "ConjureHistoryTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defer { defaults.removePersistentDomain(forName: suite) }
let instant = Date(timeIntervalSinceReferenceDate: 4_000)
let history = LaunchHistory(defaults: defaults, now: { instant })
let path = "/Applications/HistoryTests/Editor.app"
let plain = Application(url: URL(fileURLWithPath: path, isDirectory: false), name: "Editor")
let directory = Application(url: URL(fileURLWithPath: path, isDirectory: true), name: "Editor")
#expect(plain.id == directory.id)
history.recordLaunch(of: directory)
#expect(history.suggestions(in: [historyApplication("Alpha"), plain]).first?.id == plain.id)
}
@Test @MainActor
func typedSearchUsesHistoryOnlyForEqualTextRanks() {
let suite = "ConjureHistoryTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defer { defaults.removePersistentDomain(forName: suite) }
var instant = Date(timeIntervalSinceReferenceDate: 5_000)
let history = LaunchHistory(defaults: defaults, now: { instant })
let apps = ["Code", "Code Alpha", "Code Recent", "Code Frequent", "Open Code", "Unrelated"].map(historyApplication)
history.recordLaunch(of: apps[3])
history.recordLaunch(of: apps[3])
instant += 10
history.recordLaunch(of: apps[2])
for _ in 0..<3 { history.recordLaunch(of: apps[4]) }
history.recordLaunch(of: apps[5])
#expect(history.results(for: "code", in: apps).map(\.name) == [
"Code", "Code Frequent", "Code Recent", "Code Alpha", "Open Code",
])
instant += 10
history.recordLaunch(of: apps[1])
#expect(history.results(for: "code", in: apps).map(\.name) == [
"Code", "Code Frequent", "Code Alpha", "Code Recent", "Open Code",
])
let fuzzy = ["AyB", "AzB", "xAyB", "AxxxxB"].map(historyApplication)
history.recordLaunch(of: fuzzy[1])
for _ in 0..<3 { history.recordLaunch(of: fuzzy[3]) }
#expect(history.results(for: "ab", in: fuzzy).map(\.name) == [
"AzB", "AyB", "xAyB", "AxxxxB",
])
}
@Test @MainActor
func resetRankingClearsOnlySelectedIdentityAndPersistsAcrossRelaunch() {
let suite = "ConjureHistoryTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defer { defaults.removePersistentDomain(forName: suite) }
let instant = Date(timeIntervalSinceReferenceDate: 6_000)
let history = LaunchHistory(defaults: defaults, now: { instant })
let alpha = historyApplication("Editor Alpha")
let first = Application(url: URL(fileURLWithPath: "/First/Editor.app"), name: "Editor")
let second = Application(url: URL(fileURLWithPath: "/Second/Editor.app"), name: "Editor")
let apps = [alpha, first, second]
history.recordLaunch(of: second)
history.recordLaunch(of: first)
history.recordLaunch(of: first)
#expect(history.suggestions(in: apps).map(\.id) == [first.id, second.id, alpha.id])
history.resetRanking(of: first)
history.resetRanking(of: first)
#expect(history.suggestions(in: apps).map(\.id) == [second.id, first.id, alpha.id])
#expect(history.results(for: "editor", in: apps).map(\.id) == [second.id, first.id, alpha.id])
let reloaded = LaunchHistory(defaults: UserDefaults(suiteName: suite)!, now: { instant })
#expect(reloaded.suggestions(in: apps).map(\.id) == [second.id, first.id, alpha.id])
reloaded.recordLaunch(of: first)
#expect(reloaded.suggestions(in: apps).map(\.id) == [first.id, second.id, alpha.id])
}
private func historyApplication(_ name: String) -> Application {
Application(url: URL(fileURLWithPath: "/Applications/HistoryTests/\(name).app"), name: name)
}