Files
oai-swift/oAITests/ContextSelectionServiceDBTests.swift
T
rune f3c6271c9e Phase 4 tests: DatabaseService migrations + ContextSelectionService DB paths
17 tests against throwaway in-memory DatabaseService instances: all
v1-v8 tables/columns exist post-migration, settings CRUD, conversation
save/load round-trip, instance isolation between separate in-memory
queues, and ContextSelectionService's DB-coupled paths (starring,
excluded-range summaries, smartSelection end to end) that were
previously untestable.
2026-07-24 09:16:46 +02:00

121 lines
5.3 KiB
Swift

//
// ContextSelectionServiceDBTests.swift
// oAITests
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
import Testing
import Foundation
@testable import oAI
@Suite("ContextSelectionService DB-coupled paths, against a throwaway in-memory queue")
struct ContextSelectionServiceDBTests {
/// Persists messages, then loads them back so their `id`s match the DB rows
/// (saveConversation assigns fresh row ids internally, distinct from the ids
/// on the Message values passed in).
private func persistedMessages(_ db: DatabaseService, _ messages: [Message]) throws -> (conversationId: UUID, messages: [Message]) {
let saved = try db.saveConversation(name: "Test", messages: messages)
let loaded = try db.loadConversation(id: saved.id)
return (saved.id, loaded?.1 ?? [])
}
// MARK: - isMessageStarred
@Test("A message with no metadata row is not starred")
func unstarredByDefault() throws {
let db = DatabaseService.makeInMemory()
let service = ContextSelectionService(db: db)
let (_, messages) = try persistedMessages(db, [Message(role: .user, content: "hi")])
#expect(service.isMessageStarred(messages[0]) == false)
}
@Test("A message starred via setMessageStarred reports starred")
func starredAfterSetting() throws {
let db = DatabaseService.makeInMemory()
let service = ContextSelectionService(db: db)
let (_, messages) = try persistedMessages(db, [Message(role: .user, content: "hi")])
try db.setMessageStarred(messageId: messages[0].id, starred: true)
#expect(service.isMessageStarred(messages[0]) == true)
}
// MARK: - getSummariesForExcludedRange
@Test("No summaries recorded returns an empty array")
func noSummariesReturnsEmpty() throws {
let db = DatabaseService.makeInMemory()
let service = ContextSelectionService(db: db)
let (conversationId, _) = try persistedMessages(db, [Message(role: .user, content: "hi")])
let summaries = service.getSummariesForExcludedRange(conversationId: conversationId, totalMessages: 30, selectedCount: 10)
#expect(summaries.isEmpty)
}
@Test("A summary covering only excluded messages is included")
func summaryForExcludedRangeIncluded() throws {
let db = DatabaseService.makeInMemory()
let service = ContextSelectionService(db: db)
let (conversationId, _) = try persistedMessages(db, [Message(role: .user, content: "hi")])
// 30 total, 10 selected -> messages 0..<20 are excluded
try db.saveConversationSummary(conversationId: conversationId, startIndex: 0, endIndex: 15, summary: "early stuff", model: nil, tokenCount: nil)
let summaries = service.getSummariesForExcludedRange(conversationId: conversationId, totalMessages: 30, selectedCount: 10)
#expect(summaries == ["early stuff"])
}
@Test("A summary covering messages that were kept is excluded")
func summaryForKeptRangeExcluded() throws {
let db = DatabaseService.makeInMemory()
let service = ContextSelectionService(db: db)
let (conversationId, _) = try persistedMessages(db, [Message(role: .user, content: "hi")])
// 30 total, 10 selected -> messages 0..<20 are excluded; this summary ends at 25, inside the kept range
try db.saveConversationSummary(conversationId: conversationId, startIndex: 15, endIndex: 25, summary: "later stuff", model: nil, tokenCount: nil)
let summaries = service.getSummariesForExcludedRange(conversationId: conversationId, totalMessages: 30, selectedCount: 10)
#expect(summaries.isEmpty)
}
// MARK: - smartSelection (end to end through the DB seam)
@Test("A starred older message is pulled in alongside the recent window")
func starredMessagePulledIntoSelection() throws {
let db = DatabaseService.makeInMemory()
let service = ContextSelectionService(db: db)
var all: [Message] = []
let base = Date()
for i in 0..<15 {
all.append(Message(role: i % 2 == 0 ? .user : .assistant, content: "msg \(i)", timestamp: base.addingTimeInterval(Double(i))))
}
let (_, persisted) = try persistedMessages(db, all)
// Star an old message that's outside the last-10 window (index 2)
try db.setMessageStarred(messageId: persisted[2].id, starred: true)
let window = service.smartSelection(allMessages: persisted, maxTokens: 100_000, conversationId: nil)
#expect(window.messages.contains { $0.id == persisted[2].id })
}
@Test("An unstarred, unimportant old message outside the recent window is excluded")
func unstarredOldMessageExcluded() throws {
let db = DatabaseService.makeInMemory()
let service = ContextSelectionService(db: db)
var all: [Message] = []
let base = Date()
for i in 0..<15 {
all.append(Message(role: i % 2 == 0 ? .user : .assistant, content: "msg \(i)", timestamp: base.addingTimeInterval(Double(i))))
}
let (_, persisted) = try persistedMessages(db, all)
let window = service.smartSelection(allMessages: persisted, maxTokens: 100_000, conversationId: nil)
#expect(window.messages.contains { $0.id == persisted[0].id } == false)
#expect(window.excludedCount == 5)
}
}