| File: Files\HostedFileDownloadStreamTests.cs | |
| Project: ..\..\..\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. #pragma warning disable MEAI001 using System; using System.IO; using System.Threading.Tasks; using Xunit; namespace Microsoft.Extensions.AI; public class HostedFileDownloadStreamTests { [Fact] public void Defaults_ReturnNull() { using var stream = new MinimalDownloadStream([1, 2, 3]); Assert.Null(stream.MediaType); Assert.Null(stream.FileName); } [Fact] public async Task ToDataContentAsync_BuffersStreamContent() { var data = new byte[] { 10, 20, 30, 40, 50 }; using var stream = new MetadataDownloadStream(data, "application/json", "data.json"); var content = await stream.ToDataContentAsync(); Assert.Equal(data, content.Data.ToArray()); Assert.Equal("application/json", content.MediaType); Assert.Equal("data.json", content.Name); } [Fact] public async Task ToDataContentAsync_NullMediaType_DefaultsToOctetStream() { var data = new byte[] { 1, 2 }; using var stream = new MinimalDownloadStream(data); var content = await stream.ToDataContentAsync(); Assert.Equal(data, content.Data.ToArray()); Assert.Equal("application/octet-stream", content.MediaType); Assert.Null(content.Name); } [Fact] public async Task ToDataContentAsync_EmptyStream_ReturnsEmptyData() { using var stream = new MinimalDownloadStream([]); var content = await stream.ToDataContentAsync(); Assert.Empty(content.Data.ToArray()); } [Fact] public void CanWrite_ReturnsFalse() { using var stream = new MinimalDownloadStream([1, 2, 3]); Assert.False(stream.CanWrite); } [Fact] public async Task WriteApis_ThrowNotSupportedException() { using var stream = new MinimalDownloadStream([1, 2, 3]); Assert.Throws<NotSupportedException>(() => stream.SetLength(1)); Assert.Throws<NotSupportedException>(() => stream.Write([4], 0, 1)); Assert.Throws<NotSupportedException>(() => stream.WriteByte(4)); await Assert.ThrowsAsync<NotSupportedException>(() => stream.WriteAsync(new byte[] { 4 }, 0, 1)); Assert.Throws<NotSupportedException>(() => stream.BeginWrite([4], 0, 1, callback: null, state: null)); Assert.Throws<NotSupportedException>(() => stream.EndWrite(Task.CompletedTask)); #if NET Assert.Throws<NotSupportedException>(() => stream.Write([4])); await Assert.ThrowsAsync<NotSupportedException>(() => stream.WriteAsync(new byte[] { 4 }).AsTask()); #endif } /// <summary> /// Minimal implementation that does not override MediaType or FileName, testing the default behavior. /// </summary> private sealed class MinimalDownloadStream : HostedFileDownloadStream { private readonly MemoryStream _inner; public MinimalDownloadStream(byte[] data) { _inner = new MemoryStream(data); } public override bool CanRead => _inner.CanRead; public override bool CanSeek => _inner.CanSeek; public override long Length => _inner.Length; public override long Position { get => _inner.Position; set => _inner.Position = value; } public override void Flush() => _inner.Flush(); public override int Read(byte[] buffer, int offset, int count) => _inner.Read(buffer, offset, count); public override long Seek(long offset, SeekOrigin origin) => _inner.Seek(offset, origin); protected override void Dispose(bool disposing) { if (disposing) { _inner.Dispose(); } base.Dispose(disposing); } } /// <summary> /// Implementation that provides MediaType and FileName metadata. /// </summary> private sealed class MetadataDownloadStream : HostedFileDownloadStream { private readonly MemoryStream _inner; public MetadataDownloadStream(byte[] data, string? mediaType, string? fileName) { _inner = new MemoryStream(data); MediaType = mediaType; FileName = fileName; } public override string? MediaType { get; } public override string? FileName { get; } public override bool CanRead => _inner.CanRead; public override bool CanSeek => _inner.CanSeek; public override long Length => _inner.Length; public override long Position { get => _inner.Position; set => _inner.Position = value; } public override void Flush() => _inner.Flush(); public override int Read(byte[] buffer, int offset, int count) => _inner.Read(buffer, offset, count); public override long Seek(long offset, SeekOrigin origin) => _inner.Seek(offset, origin); protected override void Dispose(bool disposing) { if (disposing) { _inner.Dispose(); } base.Dispose(disposing); } } }