File: TextToSpeechClientIntegrationTests.cs
Project: ..\..\..\test\Libraries\Microsoft.Extensions.AI.Integration.Tests\Microsoft.Extensions.AI.Integration.Tests.csproj (Microsoft.Extensions.AI.Integration.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
 
#pragma warning disable CA2214 // Do not call overridable methods in constructors
 
namespace Microsoft.Extensions.AI;
 
public abstract class TextToSpeechClientIntegrationTests : IDisposable
{
    private readonly ITextToSpeechClient? _client;
 
    protected TextToSpeechClientIntegrationTests()
    {
        _client = CreateClient();
    }
 
    public void Dispose()
    {
        _client?.Dispose();
        GC.SuppressFinalize(this);
    }
 
    protected abstract ITextToSpeechClient? CreateClient();
 
    [Fact]
    public virtual async Task GetAudioAsync_SimpleText_ReturnsAudio()
    {
        SkipIfNotEnabled();
 
        var response = await _client.GetAudioAsync("Hello, world!");
 
        Assert.NotNull(response);
        Assert.NotEmpty(response.Contents);
 
        var content = Assert.Single(response.Contents);
        var dataContent = Assert.IsType<DataContent>(content);
        Assert.False(dataContent.Data.IsEmpty);
        Assert.StartsWith("audio/", dataContent.MediaType, StringComparison.Ordinal);
    }
 
    [Fact]
    public virtual async Task GetAudioAsync_WithVoice_ReturnsAudio()
    {
        SkipIfNotEnabled();
 
        var response = await _client.GetAudioAsync("The quick brown fox jumps over the lazy dog.", new TextToSpeechOptions
        {
            VoiceId = "nova",
        });
 
        Assert.NotNull(response);
        Assert.NotEmpty(response.Contents);
 
        var content = Assert.Single(response.Contents);
        var dataContent = Assert.IsType<DataContent>(content);
        Assert.False(dataContent.Data.IsEmpty);
        Assert.StartsWith("audio/", dataContent.MediaType, StringComparison.Ordinal);
    }
 
    [Fact]
    public virtual async Task GetAudioAsync_WithAudioFormat_ReturnsCorrectMediaType()
    {
        SkipIfNotEnabled();
 
        var response = await _client.GetAudioAsync("Testing audio format selection.", new TextToSpeechOptions
        {
            AudioFormat = "opus",
        });
 
        Assert.NotNull(response);
        Assert.NotEmpty(response.Contents);
 
        var content = Assert.Single(response.Contents);
        var dataContent = Assert.IsType<DataContent>(content);
        Assert.False(dataContent.Data.IsEmpty);
        Assert.Equal("audio/opus", dataContent.MediaType);
    }
 
    [Fact]
    public virtual async Task GetAudioAsync_WithSpeed_ReturnsAudio()
    {
        SkipIfNotEnabled();
 
        var response = await _client.GetAudioAsync("This should be spoken quickly.", new TextToSpeechOptions
        {
            Speed = 1.5f,
        });
 
        Assert.NotNull(response);
        Assert.NotEmpty(response.Contents);
 
        var content = Assert.Single(response.Contents);
        var dataContent = Assert.IsType<DataContent>(content);
        Assert.False(dataContent.Data.IsEmpty);
    }
 
    [Fact]
    public virtual async Task GetStreamingAudioAsync_SimpleText_ReturnsUpdates()
    {
        SkipIfNotEnabled();
 
        int updateCount = 0;
        await foreach (var update in _client.GetStreamingAudioAsync("Hello, world!"))
        {
            updateCount++;
            Assert.NotNull(update);
 
            var dataContents = update.Contents.OfType<DataContent>().ToList();
            Assert.NotEmpty(dataContents);
 
            foreach (var dataContent in dataContents)
            {
                Assert.False(dataContent.Data.IsEmpty);
                Assert.StartsWith("audio/", dataContent.MediaType, StringComparison.Ordinal);
            }
        }
 
        Assert.True(updateCount > 0, "Expected at least one streaming update.");
    }
 
    [MemberNotNull(nameof(_client))]
    protected void SkipIfNotEnabled()
    {
        string? skipIntegration = TestRunnerConfiguration.Instance["SkipIntegrationTests"];
 
        Assert.SkipUnless(skipIntegration is null && _client is not null, "Client is not enabled.");
    }
}