using System.Net; using CartWise.Infrastructure.Integrations.OpenFoodFacts; using Microsoft.Extensions.Logging.Abstractions; namespace CartWise.Application.Tests; public class OpenFoodFactsProductDataProviderTests { [Fact] public async Task FindByBarcodeAsync_ReturnsMappedResultWhenFound() { const string json = """ { "status": 1, "product": { "product_name": "Peanut Butter", "brands": "Jif, Some Co-Brand", "quantity": "16 oz", "image_url": "https://example.com/image.jpg", "code": "051500255516" } } """; var provider = CreateProvider(HttpStatusCode.OK, json); var result = await provider.FindByBarcodeAsync("051500255516"); Assert.NotNull(result); Assert.Equal("Peanut Butter", result!.Name); Assert.Equal("Jif", result.BrandName); Assert.Equal(16m, result.SizeValue); Assert.Equal("oz", result.SizeUnit); Assert.Equal("051500255516", result.SourceExternalId); } [Fact] public async Task FindByBarcodeAsync_ReturnsNullWhenStatusIsNotFound() { const string json = """{ "status": 0 }"""; var provider = CreateProvider(HttpStatusCode.OK, json); var result = await provider.FindByBarcodeAsync("000000000000"); Assert.Null(result); } [Fact] public async Task FindByBarcodeAsync_ReturnsNullOnHttpFailure() { var provider = CreateProvider(HttpStatusCode.InternalServerError, "error"); var result = await provider.FindByBarcodeAsync("051500255516"); Assert.Null(result); } [Fact] public async Task FindByBarcodeAsync_ReturnsNullOnMalformedJson() { var provider = CreateProvider(HttpStatusCode.OK, "{not valid json"); var result = await provider.FindByBarcodeAsync("051500255516"); Assert.Null(result); } private static OpenFoodFactsProductDataProvider CreateProvider(HttpStatusCode statusCode, string content) { var handler = new FakeHttpMessageHandler(statusCode, content); var httpClient = new HttpClient(handler) { BaseAddress = new Uri("https://off.example.com/") }; return new OpenFoodFactsProductDataProvider(httpClient, NullLogger.Instance); } private sealed class FakeHttpMessageHandler : HttpMessageHandler { private readonly HttpStatusCode _statusCode; private readonly string _content; public FakeHttpMessageHandler(HttpStatusCode statusCode, string content) { _statusCode = statusCode; _content = content; } protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = new HttpResponseMessage(_statusCode) { Content = new StringContent(_content) }; return Task.FromResult(response); } } }