Add song project serialization tests
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import Foundation
|
||||||
import MusicAssistantCore
|
import MusicAssistantCore
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
@@ -365,4 +366,108 @@ final class SongProjectModelTests: XCTestCase {
|
|||||||
XCTAssertNil(project.emotionalArcPoint(for: "arc-chorus"))
|
XCTAssertNil(project.emotionalArcPoint(for: "arc-chorus"))
|
||||||
XCTAssertNil(project.productionDirection(for: "prod-verse"))
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ requirement is missing and blocks implementation, record it in
|
|||||||
- [x] Model language/dialect and Arabic pronunciation settings.
|
- [x] Model language/dialect and Arabic pronunciation settings.
|
||||||
- [x] Model BPM, key, scale and maqam with Manual/Auto state.
|
- [x] Model BPM, key, scale and maqam with Manual/Auto state.
|
||||||
- [x] Model emotional arc and production directions.
|
- [x] Model emotional arc and production directions.
|
||||||
- [ ] Add serialization tests.
|
- [x] Add serialization tests.
|
||||||
|
|
||||||
## Phase 2 --- Project Persistence & Versions
|
## Phase 2 --- Project Persistence & Versions
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user