| File: Realtime\RealtimeClientBuilderTests.cs | |
| Project: ..\..\..\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj (Microsoft.Extensions.AI.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.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Xunit; #pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. namespace Microsoft.Extensions.AI; public class RealtimeClientBuilderTests { [Fact] public void Ctor_NullClient_Throws() { Assert.Throws<ArgumentNullException>("innerClient", () => new RealtimeClientBuilder((IRealtimeClient)null!)); } [Fact] public void Ctor_NullFactory_Throws() { Assert.Throws<ArgumentNullException>("innerClientFactory", () => new RealtimeClientBuilder((Func<IServiceProvider, IRealtimeClient>)null!)); } [Fact] public void Build_WithNoMiddleware_ReturnsInnerClient() { using var inner = new TestRealtimeClient(); var builder = new RealtimeClientBuilder(inner); var result = builder.Build(); Assert.Same(inner, result); } [Fact] public void Build_WithFactory_UsesFactory() { using var inner = new TestRealtimeClient(); var builder = new RealtimeClientBuilder(_ => inner); var result = builder.Build(); Assert.Same(inner, result); } [Fact] public void Use_NullClientFactory_Throws() { using var inner = new TestRealtimeClient(); var builder = new RealtimeClientBuilder(inner); Assert.Throws<ArgumentNullException>("clientFactory", () => builder.Use((Func<IRealtimeClient, IRealtimeClient>)null!)); Assert.Throws<ArgumentNullException>("clientFactory", () => builder.Use((Func<IRealtimeClient, IServiceProvider, IRealtimeClient>)null!)); } [Fact] public void Build_PipelineOrder_FirstAddedIsOutermost() { var callOrder = new List<string>(); using var inner = new TestRealtimeClient(); var builder = new RealtimeClientBuilder(inner); builder.Use(client => new OrderTrackingClient(client, "first", callOrder)); builder.Use(client => new OrderTrackingClient(client, "second", callOrder)); using var pipeline = builder.Build(); // The outermost should be "first" (added first) var outermost = Assert.IsType<OrderTrackingClient>(pipeline); Assert.Equal("first", outermost.Name); var middle = Assert.IsType<OrderTrackingClient>(outermost.GetInner()); Assert.Equal("second", middle.Name); Assert.Same(inner, middle.GetInner()); } [Fact] public void Build_WithServiceProvider_PassesToFactory() { IServiceProvider? capturedServices = null; using var inner = new TestRealtimeClient(); var builder = new RealtimeClientBuilder(inner); builder.Use((client, services) => { capturedServices = services; return client; }); var services = new EmptyServiceProvider(); builder.Build(services); Assert.Same(services, capturedServices); } [Fact] public void Build_NullServiceProvider_UsesEmptyProvider() { IServiceProvider? capturedServices = null; using var inner = new TestRealtimeClient(); var builder = new RealtimeClientBuilder(inner); builder.Use((client, services) => { capturedServices = services; return client; }); builder.Build(null); Assert.NotNull(capturedServices); } [Fact] public void Use_ReturnsSameBuilder_ForChaining() { using var inner = new TestRealtimeClient(); var builder = new RealtimeClientBuilder(inner); var returned = builder.Use(c => c); Assert.Same(builder, returned); } [Fact] public void AsBuilder_NullClient_Throws() { Assert.Throws<ArgumentNullException>("innerClient", () => ((IRealtimeClient)null!).AsBuilder()); } [Fact] public void AsBuilder_ReturnsBuilder() { using var inner = new TestRealtimeClient(); var builder = inner.AsBuilder(); Assert.NotNull(builder); Assert.Same(inner, builder.Build()); } private sealed class TestRealtimeClient : IRealtimeClient { public Task<IRealtimeClientSession> CreateSessionAsync(RealtimeSessionOptions? options = null, CancellationToken cancellationToken = default) => Task.FromResult<IRealtimeClientSession>(new TestRealtimeClientSession()); public object? GetService(Type serviceType, object? serviceKey = null) => serviceKey is null && serviceType.IsInstanceOfType(this) ? this : null; public void Dispose() { } } private sealed class OrderTrackingClient : DelegatingRealtimeClient { public string Name { get; } private readonly List<string> _callOrder; public OrderTrackingClient(IRealtimeClient inner, string name, List<string> callOrder) : base(inner) { Name = name; _callOrder = callOrder; } public IRealtimeClient GetInner() => InnerClient; public override async Task<IRealtimeClientSession> CreateSessionAsync( RealtimeSessionOptions? options = null, CancellationToken cancellationToken = default) { _callOrder.Add(Name); return await base.CreateSessionAsync(options, cancellationToken); } } private sealed class EmptyServiceProvider : IServiceProvider { public object? GetService(Type serviceType) => null; } }