test: add talk config contract fixtures

This commit is contained in:
Peter Steinberger
2026-03-08 16:11:03 +00:00
parent 8d3d742c6a
commit dc5645d459
4 changed files with 281 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
package ai.openclaw.app.voice
import java.io.File
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test
@Serializable
private data class TalkConfigContractFixture(
@SerialName("selectionCases") val selectionCases: List<SelectionCase>,
) {
@Serializable
data class SelectionCase(
val id: String,
val defaultProvider: String,
val payloadValid: Boolean,
val expectedSelection: ExpectedSelection? = null,
val talk: JsonObject,
)
@Serializable
data class ExpectedSelection(
val provider: String,
val normalizedPayload: Boolean,
val voiceId: String? = null,
)
}
class TalkModeConfigContractTest {
private val json = Json { ignoreUnknownKeys = true }
@Test
fun selectionFixtures() {
for (fixture in loadFixtures().selectionCases) {
val selection = TalkModeManager.selectTalkProviderConfig(fixture.talk)
val expected = fixture.expectedSelection
if (expected == null) {
assertNull(fixture.id, selection)
continue
}
assertNotNull(fixture.id, selection)
assertEquals(fixture.id, expected.provider, selection?.provider)
assertEquals(fixture.id, expected.normalizedPayload, selection?.normalizedPayload)
assertEquals(
fixture.id,
expected.voiceId,
(selection?.config?.get("voiceId") as? JsonPrimitive)?.content,
)
assertEquals(fixture.id, true, fixture.payloadValid)
}
}
private fun loadFixtures(): TalkConfigContractFixture {
val fixturePath = findFixtureFile()
return json.decodeFromString(File(fixturePath).readText())
}
private fun findFixtureFile(): String {
val startDir = System.getProperty("user.dir") ?: error("user.dir unavailable")
var current = File(startDir).absoluteFile
while (true) {
val candidate = File(current, "test-fixtures/talk-config-contract.json")
if (candidate.exists()) {
return candidate.absolutePath
}
current = current.parentFile ?: break
}
error("talk-config-contract.json not found from $startDir")
}
}

View File

@@ -0,0 +1,60 @@
import Foundation
import OpenClawKit
import Testing
private struct TalkConfigContractFixture: Decodable {
let selectionCases: [SelectionCase]
struct SelectionCase: Decodable {
let id: String
let defaultProvider: String
let payloadValid: Bool
let expectedSelection: ExpectedSelection?
let talk: [String: AnyCodable]
}
struct ExpectedSelection: Decodable {
let provider: String
let normalizedPayload: Bool
let voiceId: String?
}
}
private enum TalkConfigContractFixtureLoader {
static func load() throws -> TalkConfigContractFixture {
let fixtureURL = try self.findFixtureURL(startingAt: URL(fileURLWithPath: #filePath))
let data = try Data(contentsOf: fixtureURL)
return try JSONDecoder().decode(TalkConfigContractFixture.self, from: data)
}
private static func findFixtureURL(startingAt fileURL: URL) throws -> URL {
var directory = fileURL.deletingLastPathComponent()
while directory.path != "/" {
let candidate = directory.appendingPathComponent("test-fixtures/talk-config-contract.json")
if FileManager.default.fileExists(atPath: candidate.path) {
return candidate
}
directory.deleteLastPathComponent()
}
throw NSError(domain: "TalkConfigContractFixtureLoader", code: 1)
}
}
struct TalkConfigContractTests {
@Test func selectionFixtures() throws {
for fixture in try TalkConfigContractFixtureLoader.load().selectionCases {
let selection = TalkConfigParsing.selectProviderConfig(
fixture.talk,
defaultProvider: fixture.defaultProvider)
if let expected = fixture.expectedSelection {
#expect(selection != nil)
#expect(selection?.provider == expected.provider)
#expect(selection?.normalizedPayload == expected.normalizedPayload)
#expect(selection?.config["voiceId"]?.stringValue == expected.voiceId)
} else {
#expect(selection == nil)
}
#expect(fixture.payloadValid == (selection != nil))
}
}
}

View File

@@ -0,0 +1,57 @@
import fs from "node:fs";
import { describe, expect, it } from "vitest";
import { validateTalkConfigResult } from "./index.js";
type ExpectedSelection = {
provider: string;
normalizedPayload: boolean;
voiceId?: string;
};
type SelectionContractCase = {
id: string;
defaultProvider: string;
payloadValid: boolean;
expectedSelection: ExpectedSelection | null;
talk: Record<string, unknown>;
};
type TalkConfigContractFixture = {
selectionCases: SelectionContractCase[];
};
const fixturePath = new URL("../../../test-fixtures/talk-config-contract.json", import.meta.url);
const fixtures = JSON.parse(fs.readFileSync(fixturePath, "utf-8")) as TalkConfigContractFixture;
describe("talk.config contract fixtures", () => {
for (const fixture of fixtures.selectionCases) {
it(fixture.id, () => {
const payload = { config: { talk: fixture.talk } };
if (fixture.payloadValid) {
expect(validateTalkConfigResult(payload)).toBe(true);
} else {
expect((payload.config.talk as { resolved?: unknown }).resolved).toBeUndefined();
}
if (!fixture.expectedSelection) {
return;
}
const talk = payload.config.talk as {
resolved?: {
provider?: string;
config?: {
voiceId?: string;
};
};
voiceId?: string;
};
expect(talk.resolved?.provider ?? fixture.defaultProvider).toBe(
fixture.expectedSelection.provider,
);
expect(talk.resolved?.config?.voiceId ?? talk.voiceId).toBe(
fixture.expectedSelection.voiceId,
);
});
}
});

View File

@@ -0,0 +1,88 @@
{
"selectionCases": [
{
"id": "canonical_resolved_wins",
"defaultProvider": "elevenlabs",
"payloadValid": true,
"expectedSelection": {
"provider": "elevenlabs",
"normalizedPayload": true,
"voiceId": "voice-resolved"
},
"talk": {
"resolved": {
"provider": "elevenlabs",
"config": {
"voiceId": "voice-resolved"
}
},
"provider": "elevenlabs",
"providers": {
"elevenlabs": {
"voiceId": "voice-normalized"
}
},
"voiceId": "voice-legacy"
}
},
{
"id": "normalized_missing_resolved",
"defaultProvider": "elevenlabs",
"payloadValid": false,
"expectedSelection": null,
"talk": {
"provider": "elevenlabs",
"providers": {
"elevenlabs": {
"voiceId": "voice-normalized"
}
},
"voiceId": "voice-legacy"
}
},
{
"id": "provider_mismatch_missing_resolved",
"defaultProvider": "elevenlabs",
"payloadValid": false,
"expectedSelection": null,
"talk": {
"provider": "acme",
"providers": {
"elevenlabs": {
"voiceId": "voice-normalized"
}
}
}
},
{
"id": "ambiguous_providers_missing_resolved",
"defaultProvider": "elevenlabs",
"payloadValid": false,
"expectedSelection": null,
"talk": {
"providers": {
"acme": {
"voiceId": "voice-acme"
},
"elevenlabs": {
"voiceId": "voice-normalized"
}
}
}
},
{
"id": "legacy_payload_fallback",
"defaultProvider": "elevenlabs",
"payloadValid": true,
"expectedSelection": {
"provider": "elevenlabs",
"normalizedPayload": false,
"voiceId": "voice-legacy"
},
"talk": {
"voiceId": "voice-legacy",
"apiKey": "legacy-key"
}
}
]
}