File: Image\ImageGeneratorTests.cs
Web Access
Project: src\test\Libraries\Microsoft.Extensions.AI.Abstractions.Tests\Microsoft.Extensions.AI.Abstractions.Tests.csproj (Microsoft.Extensions.AI.Abstractions.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.Drawing;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
 
namespace Microsoft.Extensions.AI;
 
public class ImageGeneratorTests
{
    [Fact]
    public void GetService_WithServiceKey_ReturnsNull()
    {
        using var generator = new TestImageGenerator();
        generator.GetServiceCallback = (serviceType, serviceKey) =>
        {
            // When serviceKey is not null, should return null per interface contract
            return serviceKey is not null ? null : new object();
        };
 
        var result = generator.GetService(typeof(object), "someKey");
        Assert.Null(result);
    }
 
    [Fact]
    public void GetService_WithoutServiceKey_CallsCallback()
    {
        using var generator = new TestImageGenerator();
        var expectedResult = new object();
 
        generator.GetServiceCallback = (serviceType, serviceKey) =>
        {
            Assert.Equal(typeof(object), serviceType);
            Assert.Null(serviceKey);
            return expectedResult;
        };
 
        var result = generator.GetService(typeof(object));
        Assert.Same(expectedResult, result);
    }
 
    [Fact]
    public async Task GenerateImagesAsync_CallsCallback()
    {
        var expectedResponse = new ImageGenerationResponse();
        var expectedOptions = new ImageGenerationOptions();
        using var cts = new CancellationTokenSource();
        var expectedRequest = new ImageGenerationRequest("test prompt");
 
        using var generator = new TestImageGenerator
        {
            GenerateImagesAsyncCallback = (request, options, cancellationToken) =>
            {
                Assert.Same(expectedRequest, request);
                Assert.Same(expectedOptions, options);
                Assert.Equal(cts.Token, cancellationToken);
                return Task.FromResult(expectedResponse);
            }
        };
 
        var result = await generator.GenerateAsync(expectedRequest, expectedOptions, cts.Token);
        Assert.Same(expectedResponse, result);
    }
 
    [Fact]
    public async Task GenerateImagesAsync_NoCallback_ReturnsEmptyResponse()
    {
        using var generator = new TestImageGenerator();
        var result = await generator.GenerateAsync(new ImageGenerationRequest("test prompt"), null);
        Assert.NotNull(result);
        Assert.Empty(result.Contents);
    }
 
    [Fact]
    public void Dispose_SetsFlag()
    {
        var generator = new TestImageGenerator();
        Assert.False(generator.DisposeInvoked);
 
        generator.Dispose();
        Assert.True(generator.DisposeInvoked);
    }
 
    [Fact]
    public void Dispose_MultipleCallsSafe()
    {
        var generator = new TestImageGenerator();
 
        generator.Dispose();
        Assert.True(generator.DisposeInvoked);
 
        // Second dispose should not throw
#pragma warning disable S3966
        generator.Dispose();
#pragma warning restore S3966
        Assert.True(generator.DisposeInvoked);
    }
 
    [Fact]
    public async Task GenerateImagesAsync_WithOptions_PassesThroughCorrectly()
    {
        var options = new ImageGenerationOptions
        {
            ResponseFormat = ImageGenerationResponseFormat.Data,
            Count = 3,
            ImageSize = new Size(1024, 768),
            MediaType = "image/png",
            ModelId = "test-model",
        };
 
        var expectedRequest = new ImageGenerationRequest("test prompt");
 
        using var generator = new TestImageGenerator
        {
            GenerateImagesAsyncCallback = (request, receivedOptions, cancellationToken) =>
            {
                Assert.Same(expectedRequest, request);
                Assert.Same(options, receivedOptions);
                return Task.FromResult(new ImageGenerationResponse());
            }
        };
 
        await generator.GenerateAsync(expectedRequest, options);
    }
 
    [Fact]
    public async Task GenerateImagesAsync_WithEditRequest_PassesThroughCorrectly()
    {
        var options = new ImageGenerationOptions
        {
            ResponseFormat = ImageGenerationResponseFormat.Uri,
            Count = 2,
            MediaType = "image/jpeg",
            ModelId = "edit-model",
        };
 
        AIContent[] originalImages = [new DataContent((byte[])[1, 2, 3, 4], "image/png")];
        var expectedRequest = new ImageGenerationRequest("edit prompt", originalImages);
 
        using var generator = new TestImageGenerator
        {
            GenerateImagesAsyncCallback = (request, receivedOptions, cancellationToken) =>
            {
                Assert.Same(expectedRequest, request);
                Assert.Same(options, receivedOptions);
                return Task.FromResult(new ImageGenerationResponse());
            }
        };
 
        await generator.GenerateAsync(expectedRequest, options);
    }
}