Files
meeting-assistant/MeetingAssistant.Tests/AzureSpeechStreamingTranscriptionProviderTests.cs
T
2026-05-27 12:55:17 +02:00

159 lines
5.3 KiB
C#

using MeetingAssistant.Recording;
using MeetingAssistant.Transcription;
using Microsoft.CognitiveServices.Speech;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
namespace MeetingAssistant.Tests;
public sealed class AzureSpeechStreamingTranscriptionProviderTests
{
[Fact]
public async Task TranscribeFailsClearlyWhenKeyIsMissing()
{
var provider = new AzureSpeechStreamingTranscriptionProvider(
Options.Create(new MeetingAssistantOptions
{
AzureSpeech = new AzureSpeechOptions
{
Region = "germanywestcentral",
KeyEnv = $"MEETING_ASSISTANT_MISSING_AZURE_KEY_{Guid.NewGuid():N}"
}
}),
NullLogger<AzureSpeechStreamingTranscriptionProvider>.Instance);
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
{
await foreach (var _ in provider.TranscribeAsync(ReadSingleChunk(), SpeechRecognitionPipelineOptions.Default, CancellationToken.None))
{
}
});
Assert.Contains("Azure Speech key is not configured", exception.Message);
}
[Fact]
public void AutoDetectLanguagesAreUsedOnlyWhenLanguageIsAuto()
{
Assert.Equal(
["de-DE", "en-US"],
AzureSpeechStreamingTranscriptionProvider.GetAutoDetectLanguages(new AzureSpeechOptions
{
Language = "auto",
AutoDetectLanguages = ["de-DE", "en-US", "de-DE", " "]
}));
Assert.Empty(AzureSpeechStreamingTranscriptionProvider.GetAutoDetectLanguages(new AzureSpeechOptions
{
Language = "de-DE",
AutoDetectLanguages = ["de-DE", "en-US"]
}));
}
[Fact]
public void NormalizeDictationWordsTrimsAndDeduplicatesPhrases()
{
Assert.Equal(
["PBI", "Product Backlog Item"],
AzureSpeechStreamingTranscriptionProvider.NormalizeDictationWords([
" PBI ",
"pbi",
"",
"Product Backlog Item"
]));
}
[Fact]
public void CreateSpeechConfigSkipsConfiguredPostProcessingOptionForConversationTranscriber()
{
var provider = new AzureSpeechStreamingTranscriptionProvider(
Options.Create(new MeetingAssistantOptions
{
AzureSpeech = new AzureSpeechOptions
{
Endpoint = "wss://westeurope.stt.speech.microsoft.com/speech/universal/v2",
Language = "de-DE",
Key = "test-key",
PostProcessingOption = "PostRefinement"
}
}),
NullLogger<AzureSpeechStreamingTranscriptionProvider>.Instance);
var speechConfig = provider.CreateSpeechConfig();
Assert.True(string.IsNullOrEmpty(
speechConfig.GetProperty(PropertyId.SpeechServiceResponse_PostProcessingOption)));
}
[Fact]
public void CreateSpeechConfigDoesNotApplyBlankPostProcessingOption()
{
var provider = new AzureSpeechStreamingTranscriptionProvider(
Options.Create(new MeetingAssistantOptions
{
AzureSpeech = new AzureSpeechOptions
{
Endpoint = "wss://westeurope.stt.speech.microsoft.com/speech/universal/v2",
Language = "de-DE",
Key = "test-key",
PostProcessingOption = " "
}
}),
NullLogger<AzureSpeechStreamingTranscriptionProvider>.Instance);
var speechConfig = provider.CreateSpeechConfig();
Assert.True(string.IsNullOrEmpty(
speechConfig.GetProperty(PropertyId.SpeechServiceResponse_PostProcessingOption)));
}
[Fact]
public void ResolveKeyFallsBackToUserEnvironment()
{
var keyEnv = $"MEETING_ASSISTANT_AZURE_KEY_{Guid.NewGuid():N}";
try
{
Environment.SetEnvironmentVariable(keyEnv, "user-key", EnvironmentVariableTarget.User);
Assert.Equal("user-key", AzureSpeechStreamingTranscriptionProvider.ResolveKey(new AzureSpeechOptions
{
KeyEnv = keyEnv
}));
}
finally
{
Environment.SetEnvironmentVariable(keyEnv, null, EnvironmentVariableTarget.User);
}
}
[Fact]
public void CreateSpeechConfigUsesSubscriptionWhenEndpointIsBlank()
{
var speechConfig = AzureSpeechStreamingTranscriptionProvider.CreateSpeechConfig(
new AzureSpeechOptions
{
Endpoint = "",
Region = "westeurope"
},
"test-key");
Assert.NotNull(speechConfig);
}
[Theory]
[InlineData(null, "Continuous")]
[InlineData("", "Continuous")]
[InlineData("continuous", "Continuous")]
[InlineData("AtStart", "AtStart")]
public void LanguageIdModeDefaultsToContinuous(string? configured, string expected)
{
Assert.Equal(expected, AzureSpeechStreamingTranscriptionProvider.NormalizeLanguageIdMode(configured));
}
private static async IAsyncEnumerable<AudioChunk> ReadSingleChunk()
{
await Task.Yield();
yield return new AudioChunk(new byte[320], 16000, 1);
}
}