// // ConversationMergeServiceTests.swift // oAITests // // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 // Copyright (C) 2026 Rune Olsen import Testing @testable import Confab @Suite("ConversationMergeService AI response parsing") struct ConversationMergeServiceParsingTests { @Test("Parses a clean JSON array response") func parsesCleanJSON() throws { let raw = #"[{"role": "user", "content": "hi"}, {"role": "assistant", "content": "hello"}]"# let turns = try ConversationMergeService.parseTurns(from: raw) #expect(turns == [ ConversationMergeService.MergedTurn(role: "user", content: "hi"), ConversationMergeService.MergedTurn(role: "assistant", content: "hello"), ]) } @Test("Parses a JSON array wrapped in markdown code fences") func parsesFencedJSON() throws { let raw = """ ```json [{"role": "user", "content": "hi"}] ``` """ let turns = try ConversationMergeService.parseTurns(from: raw) #expect(turns == [ConversationMergeService.MergedTurn(role: "user", content: "hi")]) } @Test("Recovers a JSON array embedded in surrounding prose") func recoversEmbeddedJSON() throws { let raw = """ Sure, here's the merged conversation: [{"role": "user", "content": "hi"}, {"role": "assistant", "content": "hello there"}] Let me know if you'd like anything else! """ let turns = try ConversationMergeService.parseTurns(from: raw) #expect(turns == [ ConversationMergeService.MergedTurn(role: "user", content: "hi"), ConversationMergeService.MergedTurn(role: "assistant", content: "hello there"), ]) } @Test("Bracket matching ignores ']' characters inside quoted content") func ignoresBracketsInsideStrings() throws { let raw = #"[{"role": "assistant", "content": "array[0] and array[1]"}]"# let turns = try ConversationMergeService.parseTurns(from: raw) #expect(turns == [ConversationMergeService.MergedTurn(role: "assistant", content: "array[0] and array[1]")]) } @Test("Throws invalidAIResponse when no JSON array is present") func throwsWhenNoJSONFound() { let raw = "I reverted the latest changes, the search function is not that important." #expect(throws: MergeError.self) { try ConversationMergeService.parseTurns(from: raw) } } @Test("Throws invalidAIResponse for an empty JSON array") func throwsForEmptyArray() { #expect(throws: MergeError.self) { try ConversationMergeService.parseTurns(from: "[]") } } }