Add song project serialization tests
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import Foundation
|
||||
import MusicAssistantCore
|
||||
import XCTest
|
||||
|
||||
@@ -365,4 +366,108 @@ final class SongProjectModelTests: XCTestCase {
|
||||
XCTAssertNil(project.emotionalArcPoint(for: "arc-chorus"))
|
||||
XCTAssertNil(project.productionDirection(for: "prod-verse"))
|
||||
}
|
||||
|
||||
func testSongProjectRoundTripsThroughJSONSerialization() throws {
|
||||
let createdAt = Date(timeIntervalSince1970: 1_700_000_000)
|
||||
let updatedAt = Date(timeIntervalSince1970: 1_700_000_120)
|
||||
let generatedAt = Date(timeIntervalSince1970: 1_700_000_240)
|
||||
let section = SongSection(
|
||||
id: "verse",
|
||||
type: .verse,
|
||||
title: "Verse",
|
||||
order: 0,
|
||||
startTime: 8,
|
||||
endTime: 38,
|
||||
lyrics: "Draft verse",
|
||||
emotion: "reflective",
|
||||
energy: 4,
|
||||
vocalDirection: "close vocal",
|
||||
productionDirection: "subtle pad"
|
||||
)
|
||||
let instrument = InstrumentTrack(
|
||||
instrumentId: "oud",
|
||||
selected: true,
|
||||
variant: "Arabic oud",
|
||||
playingStyle: "picked",
|
||||
role: "lead motif",
|
||||
autoArrangementEnabled: false,
|
||||
placements: [
|
||||
InstrumentPlacement(
|
||||
sectionId: section.id,
|
||||
startTime: section.startTime,
|
||||
endTime: section.endTime,
|
||||
direction: "answer the vocal"
|
||||
)
|
||||
]
|
||||
)
|
||||
var project = SongProject(
|
||||
id: "serialized-project",
|
||||
title: "Serializable Song",
|
||||
idea: "A multilingual cinematic song",
|
||||
duration: SongDuration(seconds: 210, description: "about three and a half minutes"),
|
||||
conversationMode: .discuss,
|
||||
languages: [LanguageSelection(id: "arabic", name: "Arabic")],
|
||||
dialects: [DialectSelection(id: "levantine", name: "Levantine", languageID: "arabic")],
|
||||
arabicPronunciationSettings: ArabicPronunciationSettings(
|
||||
isEnabled: true,
|
||||
diacritizationPolicy: .pronunciationTargeted,
|
||||
tanweenPolicy: .preserveUserInput,
|
||||
userNotes: "Keep dialect phrasing natural",
|
||||
preservedSpellings: ["habibi"]
|
||||
),
|
||||
genres: [GenreStyle(id: "cinematic-pop", name: "Cinematic Pop", aliases: ["orchestral pop"])],
|
||||
moods: [MoodTag(id: "yearning", name: "Yearning")],
|
||||
emotionalArc: [
|
||||
EmotionalArcPoint(
|
||||
id: "arc-verse",
|
||||
sectionID: section.id,
|
||||
emotion: "reflective",
|
||||
energy: 4,
|
||||
direction: "slowly opening"
|
||||
)
|
||||
],
|
||||
bpm: ManualAutoValue(mode: .manual, value: 92),
|
||||
key: ManualAutoValue(mode: .manual, value: "D"),
|
||||
scale: ManualAutoValue(mode: .auto),
|
||||
maqam: ManualAutoValue(mode: .manual, value: "Hijaz"),
|
||||
sections: [section],
|
||||
instruments: [instrument],
|
||||
vocalists: [
|
||||
Vocalist(
|
||||
id: "lead",
|
||||
label: "Lead",
|
||||
voiceType: "tenor",
|
||||
genderSelection: "male",
|
||||
performanceStyle: "sung",
|
||||
assignedSections: [section.id]
|
||||
)
|
||||
],
|
||||
lyrics: Lyrics(text: "Full lyric draft", sectionTexts: [section.id: "Draft verse"]),
|
||||
productionDirections: [
|
||||
ProductionDirection(id: "prod-verse", sectionID: section.id, text: "keep percussion sparse")
|
||||
],
|
||||
sunoOutput: SunoOutput(
|
||||
lyricsText: "Full lyric draft",
|
||||
stylePrompt: "Cinematic pop with oud",
|
||||
additionalFields: ["style": "cinematic"],
|
||||
generatedAt: generatedAt
|
||||
),
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt
|
||||
)
|
||||
project.versions = [
|
||||
SongVersion(
|
||||
id: "version-1",
|
||||
label: "Initial approved direction",
|
||||
snapshot: SongProjectSnapshot(project: project),
|
||||
createdAt: updatedAt
|
||||
)
|
||||
]
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
let data = try encoder.encode(project)
|
||||
let decodedProject = try JSONDecoder().decode(SongProject.self, from: data)
|
||||
|
||||
XCTAssertEqual(decodedProject, project)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user