File: Image\ImageGeneratorExtensionsTests.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.Threading;
using System.Threading.Tasks;
using Xunit;
 
namespace Microsoft.Extensions.AI;
 
public class ImageGeneratorExtensionsTests
{
    [Fact]
    public void GetService_InvalidArgs_Throws()
    {
        Assert.Throws<ArgumentNullException>("generator", () =>
        {
            _ = ImageGeneratorExtensions.GetService<object>(null!);
        });
    }
 
    [Fact]
    public void GetService_ValidGenerator_CallsUnderlyingGetService()
    {
        using var testGenerator = new TestImageGenerator();
        var expectedResult = new object();
        var expectedServiceKey = new object();
 
        testGenerator.GetServiceCallback = (serviceType, serviceKey) =>
        {
            Assert.Equal(typeof(object), serviceType);
            Assert.Same(expectedServiceKey, serviceKey);
            return expectedResult;
        };
 
        var result = testGenerator.GetService<object>(expectedServiceKey);
        Assert.Same(expectedResult, result);
    }
 
    [Fact]
    public void GetService_ReturnsCorrectType()
    {
        using var testGenerator = new TestImageGenerator();
        var metadata = new ImageGeneratorMetadata("test", null, "model");
 
        testGenerator.GetServiceCallback = (serviceType, serviceKey) =>
        {
            return (serviceType == typeof(ImageGeneratorMetadata)) ? metadata : null;
        };
 
        var result = testGenerator.GetService<ImageGeneratorMetadata>();
        Assert.Same(metadata, result);
 
        var nullResult = testGenerator.GetService<string>();
        Assert.Null(nullResult);
    }
 
    [Fact]
    public async Task EditImageAsync_DataContent_CallsGenerateImagesAsync()
    {
        // Arrange
        using var testGenerator = new TestImageGenerator();
        var imageData = new byte[] { 1, 2, 3, 4 };
        var dataContent = new DataContent(imageData, "image/png") { Name = "test.png" };
        var prompt = "Edit this image";
        var options = new ImageGenerationOptions { Count = 2 };
        var expectedResponse = new ImageGenerationResponse();
        var cancellationToken = new CancellationToken(canceled: false);
 
        testGenerator.GenerateImagesAsyncCallback = (request, o, ct) =>
        {
            Assert.NotNull(request.OriginalImages);
            Assert.Single(request.OriginalImages);
            Assert.Same(dataContent, Assert.Single(request.OriginalImages));
            Assert.Equal(prompt, request.Prompt);
            Assert.Same(options, o);
            Assert.Equal(cancellationToken, ct);
            return Task.FromResult(expectedResponse);
        };
 
        // Act
        var result = await testGenerator.EditImageAsync(dataContent, prompt, options, cancellationToken);
 
        // Assert
        Assert.Same(expectedResponse, result);
    }
 
    [Fact]
    public async Task EditImageAsync_DataContent_NullArguments_Throws()
    {
        using var testGenerator = new TestImageGenerator();
        var dataContent = new DataContent(new byte[] { 1, 2, 3 }, "image/png");
 
        await Assert.ThrowsAsync<ArgumentNullException>("generator", async () =>
            await ImageGeneratorExtensions.EditImageAsync(null!, dataContent, "prompt"));
 
        await Assert.ThrowsAsync<ArgumentNullException>("originalImage", async () =>
            await testGenerator.EditImageAsync(null!, "prompt"));
 
        await Assert.ThrowsAsync<ArgumentNullException>("prompt", async () =>
            await testGenerator.EditImageAsync(dataContent, null!));
    }
 
    [Fact]
    public async Task EditImageAsync_ByteArray_CallsGenerateImagesAsync()
    {
        // Arrange
        using var testGenerator = new TestImageGenerator();
        var imageData = new byte[] { 1, 2, 3, 4 };
        var fileName = "test.jpg";
        var prompt = "Edit this image";
        var options = new ImageGenerationOptions { Count = 2 };
        var expectedResponse = new ImageGenerationResponse();
        var cancellationToken = new CancellationToken(canceled: false);
 
        testGenerator.GenerateImagesAsyncCallback = (request, o, ct) =>
        {
            Assert.NotNull(request.OriginalImages);
            Assert.Single(request.OriginalImages);
            var dataContent = Assert.IsType<DataContent>(Assert.Single(request.OriginalImages));
            Assert.Equal(imageData, dataContent.Data.ToArray());
            Assert.Equal("image/jpeg", dataContent.MediaType);
            Assert.Equal(fileName, dataContent.Name);
            Assert.Equal(prompt, request.Prompt);
            Assert.Same(options, o);
            Assert.Equal(cancellationToken, ct);
            return Task.FromResult(expectedResponse);
        };
 
        // Act
        var result = await testGenerator.EditImageAsync(imageData, fileName, prompt, options, cancellationToken);
 
        // Assert
        Assert.Same(expectedResponse, result);
    }
 
    [Fact]
    public async Task EditImageAsync_ByteArray_NullGenerator_Throws()
    {
        var imageData = new byte[] { 1, 2, 3 };
 
        await Assert.ThrowsAsync<ArgumentNullException>("generator", async () =>
            await ImageGeneratorExtensions.EditImageAsync(null!, imageData, "test.png", "prompt"));
    }
 
    [Fact]
    public async Task EditImageAsync_ByteArray_NullFileName_Throws()
    {
        using var testGenerator = new TestImageGenerator();
        var imageData = new byte[] { 1, 2, 3 };
 
        await Assert.ThrowsAsync<ArgumentNullException>("fileName", async () =>
            await testGenerator.EditImageAsync(imageData, null!, "prompt"));
    }
 
    [Fact]
    public async Task EditImageAsync_ByteArray_NullPrompt_Throws()
    {
        using var testGenerator = new TestImageGenerator();
        var imageData = new byte[] { 1, 2, 3 };
 
        await Assert.ThrowsAsync<ArgumentNullException>("prompt", async () =>
            await testGenerator.EditImageAsync(imageData, "test.png", null!));
    }
 
    [Theory]
    [InlineData("test.png", "image/png")]
    [InlineData("test.jpg", "image/jpeg")]
    [InlineData("test.jpeg", "image/jpeg")]
    [InlineData("test.webp", "image/webp")]
    [InlineData("test.gif", "image/gif")]
    [InlineData("test.bmp", "image/bmp")]
    [InlineData("test.tiff", "image/tiff")]
    [InlineData("test.tif", "image/tiff")]
    [InlineData("test.unknown", "image/png")] // Unknown extension defaults to PNG
    [InlineData("TEST.PNG", "image/png")] // Case insensitive
    public async Task EditImageAsync_ByteArray_InfersCorrectMediaType(string fileName, string expectedMediaType)
    {
        // Arrange
        using var testGenerator = new TestImageGenerator();
        var imageData = new byte[] { 1, 2, 3, 4 };
        var prompt = "Edit this image";
 
        testGenerator.GenerateImagesAsyncCallback = (request, o, ct) =>
        {
            Assert.NotNull(request.OriginalImages);
            var dataContent = Assert.IsType<DataContent>(Assert.Single(request.OriginalImages));
            Assert.Equal(expectedMediaType, dataContent.MediaType);
            return Task.FromResult(new ImageGenerationResponse());
        };
 
        // Act & Assert
        await testGenerator.EditImageAsync(imageData, fileName, prompt);
    }
 
    [Fact]
    public async Task EditImageAsync_AllMethods_PassDefaultOptionsAndCancellation()
    {
        // Arrange
        using var testGenerator = new TestImageGenerator();
        var imageData = new byte[] { 1, 2, 3, 4 };
        var dataContent = new DataContent(imageData, "image/png");
        var prompt = "Edit this image";
 
        int callCount = 0;
        testGenerator.GenerateImagesAsyncCallback = (request, o, ct) =>
        {
            callCount++;
            Assert.Null(o); // Default options should be null
            Assert.Equal(CancellationToken.None, ct); // Default cancellation token
            Assert.NotNull(request.OriginalImages); // Should have original images for editing
            return Task.FromResult(new ImageGenerationResponse());
        };
 
        // Act - Test all two overloads with default parameters
        await testGenerator.EditImageAsync(dataContent, prompt);
        await testGenerator.EditImageAsync(imageData, "test.png", prompt);
 
        // Assert
        Assert.Equal(2, callCount);
    }
}