using FluentAssertions;
using foodmarket.IntegrationTests.Support;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace foodmarket.IntegrationTests;
/// Тест абстракции :
/// в default-конфиге (Storage:Type=Local) загружаем картинку товара через
/// существующий endpoint, потом читаем по public-URL через UploadsController.
/// Проверяем что file round-trip'aет.
[Collection(ApiCollection.Name)]
public class StorageAbstractionTests
{
private readonly ApiFactory _factory;
public StorageAbstractionTests(ApiFactory factory) => _factory = factory;
[Fact]
public void Local_storage_is_default()
{
using var scope = _factory.Services.CreateScope();
var storage = scope.ServiceProvider.GetRequiredService();
storage.Kind.Should().Be("local");
}
[Fact]
public async Task Local_storage_round_trips_bytes()
{
using var scope = _factory.Services.CreateScope();
var storage = scope.ServiceProvider.GetRequiredService();
var key = $"products/{Guid.NewGuid():N}/test.png";
// Минимальный валидный 1x1 PNG.
var png = Convert.FromBase64String(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNgAAIAAAUAAen63NgAAAAASUVORK5CYII=");
using (var ms = new MemoryStream(png))
{
await storage.SaveAsync(key, ms, "image/png", CancellationToken.None);
}
var read = await storage.OpenAsync(key, CancellationToken.None);
read.Should().NotBeNull();
using var output = new MemoryStream();
await read!.Value.Stream.CopyToAsync(output);
output.ToArray().Should().BeEquivalentTo(png);
await storage.DeleteAsync(key, CancellationToken.None);
var afterDelete = await storage.OpenAsync(key, CancellationToken.None);
afterDelete.Should().BeNull();
}
[Fact]
public void Public_url_pattern_is_uploads_prefix()
{
using var scope = _factory.Services.CreateScope();
var storage = scope.ServiceProvider.GetRequiredService();
storage.PublicUrl("products/abc/x.png").Should().Be("/uploads/products/abc/x.png");
// Leading slash в key не должен дублировать.
storage.PublicUrl("/products/abc/x.png").Should().Be("/uploads/products/abc/x.png");
}
}