Files
music-assistant/Tests/MusicAssistantCoreTests/SongProjectDiscussionDirectorTests.swift
T

95 lines
3.8 KiB
Swift

import MusicAssistantCore
import XCTest
final class SongProjectDiscussionDirectorTests: XCTestCase {
func testDiscussBuildsARequestAndReturnsTrimmedQuestionsWithoutChangingProject() async throws {
let project = SongProject(
id: "discussion-project",
title: "Discussion Project",
idea: "Plan a cinematic chorus",
conversationMode: .discuss,
createdAt: Date(timeIntervalSince1970: 10),
updatedAt: Date(timeIntervalSince1970: 20)
)
let aiService = RecordingDiscussionAIService(
result: SongProjectDiscussionResult(
questions: [" Should the chorus use a choir? ", " "],
notes: ["Awaiting the user's choice."]
)
)
let director = SongProjectDiscussionDirector(aiService: aiService)
let conversation = [AIConversationMessage(role: .assistant, content: "What mood should lead?")]
let result = try await director.discuss(
project: project,
userMessage: " Keep the verses intimate. ",
conversation: conversation,
localeIdentifier: "en_US"
)
let request = await aiService.recordedRequests.first
XCTAssertEqual(request?.context.userInstruction, "Keep the verses intimate.")
XCTAssertEqual(request?.context.conversation, conversation)
XCTAssertEqual(request?.context.localeIdentifier, "en_US")
XCTAssertEqual(request?.project, project)
XCTAssertEqual(result.questions, ["Should the chorus use a choir?"])
XCTAssertEqual(result.notes, ["Awaiting the user's choice."])
}
func testDiscussRejectsAutoModeAndBlankMessagesBeforeCallingAI() async throws {
let aiService = RecordingDiscussionAIService(
result: SongProjectDiscussionResult(questions: ["Unused"])
)
let director = SongProjectDiscussionDirector(aiService: aiService)
do {
_ = try await director.discuss(
project: SongProject(title: "Auto", idea: "Auto", conversationMode: .auto),
userMessage: "Ask a question."
)
XCTFail("Expected discussion mode validation to fail.")
} catch let error as SongProjectDiscussionDirectorError {
XCTAssertEqual(error, .discussionModeNotEnabled)
}
do {
_ = try await director.discuss(
project: SongProject(title: "Discuss", idea: "Discuss", conversationMode: .discuss),
userMessage: " \n "
)
XCTFail("Expected blank message validation to fail.")
} catch let error as SongProjectDiscussionDirectorError {
XCTAssertEqual(error, .emptyUserMessage)
}
let requestCount = await aiService.recordedRequests.count
XCTAssertEqual(requestCount, 0)
}
}
private actor RecordingDiscussionAIService: AIService {
private(set) var recordedRequests: [SongProjectDiscussionRequest] = []
private let result: SongProjectDiscussionResult
init(result: SongProjectDiscussionResult) {
self.result = result
}
func generateSongProject(from request: SongProjectGenerationRequest) async throws -> SongProjectGenerationResult {
SongProjectGenerationResult(project: request.seedProject ?? SongProject(title: "Unused", idea: "Unused"))
}
func discussSongProject(from request: SongProjectDiscussionRequest) async throws -> SongProjectDiscussionResult {
recordedRequests.append(request)
return result
}
func reviseLyrics(from request: LyricsRevisionRequest) async throws -> LyricsRevisionResult {
LyricsRevisionResult(lyrics: request.sourceLyrics)
}
func proposeProjectUpdate(from request: SongProjectUpdateRequest) async throws -> SongProjectUpdateResult {
SongProjectUpdateResult(project: request.project)
}
}