115 lines
4.5 KiB
Swift
115 lines
4.5 KiB
Swift
import MusicAssistantCore
|
|
import XCTest
|
|
|
|
final class StructuredAIResponseSchemaTests: XCTestCase {
|
|
func testStructuredSongProjectUpdateResponseDecodesFromJSON() throws {
|
|
let json = """
|
|
{
|
|
"project": {
|
|
"title": "Updated Song",
|
|
"idea": "A brighter chorus",
|
|
"conversationMode": "auto",
|
|
"languages": [{"id": "english", "name": "English"}],
|
|
"dialects": [],
|
|
"arabicPronunciationSettings": {
|
|
"isEnabled": false,
|
|
"diacritizationPolicy": "unspecified",
|
|
"tanweenPolicy": "unspecified",
|
|
"preservedSpellings": []
|
|
},
|
|
"genres": [{"id": "pop", "name": "Pop", "aliases": []}],
|
|
"moods": [{"id": "hopeful", "name": "Hopeful"}],
|
|
"emotionalArc": [],
|
|
"sections": [
|
|
{
|
|
"id": "chorus",
|
|
"type": "chorus",
|
|
"title": "Chorus",
|
|
"order": 0,
|
|
"lyrics": "Lift the hook higher"
|
|
}
|
|
],
|
|
"instruments": [
|
|
{
|
|
"instrumentId": "piano",
|
|
"selected": true,
|
|
"autoArrangementEnabled": true,
|
|
"placements": []
|
|
}
|
|
],
|
|
"vocalists": [],
|
|
"lyrics": {
|
|
"text": "Lift the hook higher",
|
|
"sectionTexts": {"chorus": "Lift the hook higher"}
|
|
},
|
|
"productionDirections": [],
|
|
"sunoOutput": {
|
|
"lyricsText": "Lift the hook higher",
|
|
"stylePrompt": "Hopeful pop with piano",
|
|
"additionalFields": {},
|
|
"generatedAt": "2026-09-13T18:00:00Z"
|
|
}
|
|
},
|
|
"changedScopes": ["lyrics", "structure", "sunoOutput"],
|
|
"notes": ["Updated requested creative fields."],
|
|
"followUpQuestions": ["Should the final chorus repeat?"]
|
|
}
|
|
""".data(using: .utf8)!
|
|
let decoder = JSONDecoder()
|
|
decoder.dateDecodingStrategy = .iso8601
|
|
|
|
let response = try decoder.decode(StructuredSongProjectUpdateResponse.self, from: json)
|
|
|
|
XCTAssertEqual(StructuredSongProjectUpdateResponse.schemaName, "song_project_update_response")
|
|
XCTAssertEqual(response.project.title, "Updated Song")
|
|
XCTAssertEqual(response.project.sections.first?.type, .chorus)
|
|
XCTAssertEqual(response.project.instruments.first?.instrumentId, "piano")
|
|
XCTAssertEqual(response.changedScopes, [.lyrics, .structure, .sunoOutput])
|
|
XCTAssertEqual(response.notes, ["Updated requested creative fields."])
|
|
XCTAssertEqual(response.followUpQuestions, ["Should the final chorus repeat?"])
|
|
}
|
|
|
|
func testStructuredSongProjectUpdateResponseCreatesUpdateResultWhilePreservingProjectIdentityAndVersions() {
|
|
let createdAt = Date(timeIntervalSince1970: 100)
|
|
let updatedAt = Date(timeIntervalSince1970: 200)
|
|
var existingProject = SongProject(
|
|
id: "project-id",
|
|
title: "Original",
|
|
idea: "Original idea",
|
|
createdAt: createdAt,
|
|
updatedAt: createdAt
|
|
)
|
|
let version = existingProject.createVersion(
|
|
id: "version-id",
|
|
label: "Before AI update",
|
|
createdAt: createdAt
|
|
)
|
|
let response = StructuredSongProjectUpdateResponse(
|
|
project: SongProjectSnapshot(
|
|
title: "Updated",
|
|
idea: "Updated idea",
|
|
genres: [GenreStyle(id: "cinematic", name: "Cinematic")],
|
|
lyrics: Lyrics(text: "Updated lyrics")
|
|
),
|
|
changedScopes: [.genres, .lyrics],
|
|
notes: ["Proposed focused update."],
|
|
followUpQuestions: ["Keep it minimal?"]
|
|
)
|
|
|
|
let result = response.makeUpdateResult(
|
|
updating: existingProject,
|
|
updatedAt: updatedAt
|
|
)
|
|
|
|
XCTAssertEqual(result.project.id, "project-id")
|
|
XCTAssertEqual(result.project.createdAt, createdAt)
|
|
XCTAssertEqual(result.project.updatedAt, updatedAt)
|
|
XCTAssertEqual(result.project.versions, [version])
|
|
XCTAssertEqual(result.project.title, "Updated")
|
|
XCTAssertEqual(result.project.lyrics.text, "Updated lyrics")
|
|
XCTAssertEqual(result.changedScopes, [.genres, .lyrics])
|
|
XCTAssertEqual(result.notes, ["Proposed focused update."])
|
|
XCTAssertEqual(result.followUpQuestions, ["Keep it minimal?"])
|
|
}
|
|
}
|