From c7640470c63a92a8f6a4de58c0dd9ee4ebc56c28 Mon Sep 17 00:00:00 2001 From: diyaa Date: Mon, 14 Sep 2026 22:08:04 +0200 Subject: [PATCH] Validate compiled Suno output --- .../PromptCompiler/SunoOutputValidation.swift | 29 +++++++++++++++++++ .../SunoOutputValidationTests.swift | 19 ++++++++++++ docs/TASKS.md | 2 +- 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 Sources/MusicAssistantCore/Services/PromptCompiler/SunoOutputValidation.swift create mode 100644 Tests/MusicAssistantCoreTests/SunoOutputValidationTests.swift diff --git a/Sources/MusicAssistantCore/Services/PromptCompiler/SunoOutputValidation.swift b/Sources/MusicAssistantCore/Services/PromptCompiler/SunoOutputValidation.swift new file mode 100644 index 0000000..775cc41 --- /dev/null +++ b/Sources/MusicAssistantCore/Services/PromptCompiler/SunoOutputValidation.swift @@ -0,0 +1,29 @@ +import Foundation + +public protocol SunoOutputValidating: Sendable { + func validate(_ output: CompiledSunoOutput) throws +} + +public enum SunoOutputValidationError: Error, Equatable, LocalizedError, Sendable { + case missingContent + + public var errorDescription: String? { + switch self { + case .missingContent: + return "Add lyrics or a style prompt before sending the song to Suno." + } + } +} + +public struct CompiledSunoOutputValidator: SunoOutputValidating { + public init() {} + + public func validate(_ output: CompiledSunoOutput) throws { + let lyrics = output.lyricsText.trimmingCharacters(in: .whitespacesAndNewlines) + let style = output.stylePrompt.trimmingCharacters(in: .whitespacesAndNewlines) + + guard !lyrics.isEmpty || !style.isEmpty else { + throw SunoOutputValidationError.missingContent + } + } +} diff --git a/Tests/MusicAssistantCoreTests/SunoOutputValidationTests.swift b/Tests/MusicAssistantCoreTests/SunoOutputValidationTests.swift new file mode 100644 index 0000000..a306b9a --- /dev/null +++ b/Tests/MusicAssistantCoreTests/SunoOutputValidationTests.swift @@ -0,0 +1,19 @@ +import MusicAssistantCore +import XCTest + +final class SunoOutputValidationTests: XCTestCase { + func testValidatorRejectsOutputWithoutSunoContent() { + let output = CompiledSunoOutput(lyricsText: " \n ", stylePrompt: "\t") + + XCTAssertThrowsError(try CompiledSunoOutputValidator().validate(output)) { error in + XCTAssertEqual(error as? SunoOutputValidationError, .missingContent) + } + } + + func testValidatorAllowsLyricsOrAStylePrompt() throws { + let validator = CompiledSunoOutputValidator() + + XCTAssertNoThrow(try validator.validate(CompiledSunoOutput(lyricsText: "Lyrics", stylePrompt: ""))) + XCTAssertNoThrow(try validator.validate(CompiledSunoOutput(lyricsText: "", stylePrompt: "Cinematic folk"))) + } +} diff --git a/docs/TASKS.md b/docs/TASKS.md index 9721042..af4c273 100644 --- a/docs/TASKS.md +++ b/docs/TASKS.md @@ -102,7 +102,7 @@ requirement is missing and blocks implementation, record it in appropriate. - [x] Generate style prompt from genre blend, instrumentation, vocals, tempo, harmony, emotion and production instructions. -- [ ] Validate output before handoff. +- [x] Validate output before handoff. - [ ] Keep compiler independent from UI and OpenAI client. ## Phase 8 --- Suno Handoff