package comm import "testing" // 同一(语言,性别)有多个音色时取第一个——「界面可切换、不选就用默认」的默认值就是它。 func TestPickVoiceTakesFirst(t *testing.T) { got := PickVoice(TTSProviderAzure, "zh-CN", GenderFemale) if want := "zh-CN-XiaoxiaoNeural"; got != want { t.Fatalf("PickVoice(azure,zh-CN,女) = %s,期望第一个 %s", got, want) } if n := len(VoicesOf(TTSProviderAzure, "zh-CN", GenderFemale)); n < 2 { t.Fatalf("zh-CN 女声候选应有多个(用于界面切换),实际 %d", n) } } // 语言退化:zh 能命中 zh-CN,但绝不跨语言乱兜底。 func TestVoiceLanguageFallback(t *testing.T) { if got := PickVoice(TTSProviderAzure, "zh", GenderMale); got == "" { t.Fatal("zh 应退化匹配到 zh-CN 音色") } if got := PickVoice(TTSProviderAzure, "xx-YY", GenderMale); got != "" { t.Fatalf("未知语言应返回空串(让调用方用服务商默认),实际 %s", got) } // 指定性别无音色时放开性别,也不能换语言:阿里韩语只有女声。 if got := PickVoice(TTSProviderAlibaba, "ko-KR", GenderMale); got != "kyong" { t.Fatalf("阿里 ko-KR 男声缺失应回落到该语言的女声 kyong,实际 %s", got) } } // agent 显式配过的音色优先于音色表默认值;没配过才用表里的默认。 func TestResolveAgentVoice(t *testing.T) { vm := []AgentVoice{ {Language: "zh-CN", Gender: GenderFemale, Voice: "zh-CN-XiaoyiNeural"}, {Language: "ja-JP", Gender: GenderFemale, Voice: ""}, // 空值视为没配 } if got := ResolveAgentVoice(vm, TTSProviderAzure, "zh-CN", GenderFemale); got != "zh-CN-XiaoyiNeural" { t.Fatalf("应优先用 voice_map 里运营选的音色,实际 %s", got) } // 没配 → 回落音色表默认 if got := ResolveAgentVoice(vm, TTSProviderAzure, "ja-JP", GenderFemale); got != "ja-JP-NanamiNeural" { t.Fatalf("voice_map 空值应回落音色表默认,实际 %s", got) } if got := ResolveAgentVoice(nil, TTSProviderAzure, "en-US", GenderMale); got != "en-US-GuyNeural" { t.Fatalf("无 voice_map 应取音色表第一个男声,实际 %s", got) } } // 未知服务商不能瞎给音色(会拿 Azure 的 id 去调阿里)。 func TestUnknownProvider(t *testing.T) { if n := len(TTSVoices("volcengine")); n != 0 { t.Fatalf("音色表未覆盖的服务商应返回空,实际 %d 条", n) } if got := PickVoice("volcengine", "zh-CN", GenderFemale); got != "" { t.Fatalf("未覆盖服务商应返回空串,实际 %s", got) } }