Renamed methods across multiple client classes for consistency, shortening and aligning naming conventions (e.g., `CheckAttachmentsAsync` → `CheckAsync`, `ValidatePdfAsync` → `ValidateAsync`). Updated corresponding interfaces, unit tests, and documentation to reflect the new method names. Standardized method signatures to support both `Stream` and `byte[]` overloads consistently. Improved error handling in tests and updated examples in the README for batch processing and validation scenarios. Enhanced API endpoint overview for clarity.
135 lines
5.0 KiB
C#
135 lines
5.0 KiB
C#
using DocumentService.Application.Common.DTOs;
|
||
using DocumentService.Client.Clients;
|
||
using DocumentService.Client.Interfaces;
|
||
using FluentAssertions;
|
||
using Microsoft.Extensions.Logging.Abstractions;
|
||
using System.Net;
|
||
using System.Net.Http;
|
||
using System.Text.Json;
|
||
|
||
namespace DocumentService.Tests.Unit.Client;
|
||
|
||
/// <summary>
|
||
/// Unit tests for <see cref="SwissQrCodeClient"/>.
|
||
/// All tests use a fake <see cref="MockHttpMessageHandler"/> <20> no real HTTP calls are made.
|
||
/// </summary>
|
||
public class SwissQrCodeClientTests
|
||
{
|
||
// ?? helpers ????????????????????????????????????????????????????????????
|
||
|
||
private static (SwissQrCodeClient client, MockHttpMessageHandler handler) Build<T>(T body)
|
||
{
|
||
var handler = MockHttpMessageHandler.ReturningJson(body);
|
||
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
||
var client = new SwissQrCodeClient(httpClient, NullLogger<SwissQrCodeClient>.Instance);
|
||
return (client, handler);
|
||
}
|
||
|
||
private static byte[] FakePdfBytes() => "fake-pdf-content"u8.ToArray();
|
||
|
||
// ?? ExtractAsync (Stream) <20> parsed Bill ??????????????????????
|
||
|
||
[Fact]
|
||
public async Task ExtractAsync_Stream_ParsedMode_SendsMultipartToCorrectEndpoint()
|
||
{
|
||
// Arrange
|
||
var expected = new SwissQrCodeExtractionResult(
|
||
Bill: new SwissQrBillDto
|
||
{
|
||
Version = "V2_0",
|
||
Currency = "CHF",
|
||
Account = "CH9300762011623852957",
|
||
Creditor = new AddressDto { Name = "Test AG", Town = "Bern", CountryCode = "CH", Type = "S", PostalCode = "3000" },
|
||
ReferenceType = "NON"
|
||
},
|
||
RawLines: []
|
||
);
|
||
var (client, handler) = Build(expected);
|
||
|
||
// Act
|
||
var result = await client.ExtractAsync(new MemoryStream(FakePdfBytes()), raw: false);
|
||
|
||
// Assert
|
||
result.Should().NotBeNull();
|
||
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/qr-code/extract-swiss?raw=False");
|
||
handler.LastRequest.Content.Should().BeOfType<MultipartFormDataContent>();
|
||
}
|
||
|
||
[Fact]
|
||
public async Task ExtractAsync_Stream_RawMode_SendsRawFlagInUrl()
|
||
{
|
||
// Arrange
|
||
var expected = new SwissQrCodeExtractionResult(Bill: null, RawLines: ["SPC", "0200", "1"]);
|
||
var (client, handler) = Build(expected);
|
||
|
||
// Act
|
||
var result = await client.ExtractAsync(new MemoryStream(FakePdfBytes()), raw: true);
|
||
|
||
// Assert
|
||
result.RawLines.Should().HaveCount(3).And.StartWith("SPC");
|
||
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/qr-code/extract-swiss?raw=True");
|
||
}
|
||
|
||
// ?? ExtractAsync (byte[]) ????????????????????????????????????
|
||
|
||
[Fact]
|
||
public async Task ExtractAsync_Bytes_SendsJsonWithBase64()
|
||
{
|
||
// Arrange
|
||
var expected = new SwissQrCodeExtractionResult(Bill: null, RawLines: []);
|
||
var (client, handler) = Build(expected);
|
||
|
||
// Act
|
||
await client.ExtractAsync(FakePdfBytes(), raw: false);
|
||
|
||
// Assert
|
||
handler.LastRequest!.Content.Should().NotBeNull();
|
||
handler.LastRequest.Content!.Headers.ContentType!.MediaType.Should().Be("application/json");
|
||
var body = await handler.LastRequest.Content!.ReadAsStringAsync();
|
||
var doc = JsonDocument.Parse(body);
|
||
doc.RootElement.GetProperty("base64Pdf").GetString().Should().NotBeNullOrEmpty();
|
||
}
|
||
|
||
[Fact]
|
||
public async Task ExtractAsync_Bytes_RawMode_IncludesRawFlagInUrl()
|
||
{
|
||
// Arrange
|
||
var expected = new SwissQrCodeExtractionResult(Bill: null, RawLines: ["SPC"]);
|
||
var (client, handler) = Build(expected);
|
||
|
||
// Act
|
||
await client.ExtractAsync(FakePdfBytes(), raw: true);
|
||
|
||
// Assert
|
||
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/qr-code/extract-swiss?raw=True");
|
||
}
|
||
|
||
// ?? HTTP error propagation ??????????????????????????????????????????????
|
||
|
||
[Fact]
|
||
public async Task ExtractAsync_WhenApiReturns404_ThrowsHttpRequestException()
|
||
{
|
||
// Arrange
|
||
var handler = MockHttpMessageHandler.ReturningStatus(HttpStatusCode.NotFound);
|
||
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
||
var client = new SwissQrCodeClient(httpClient, NullLogger<SwissQrCodeClient>.Instance);
|
||
|
||
// Act & Assert
|
||
await client.Invoking(c => c.ExtractAsync(new MemoryStream(FakePdfBytes())))
|
||
.Should().ThrowAsync<HttpRequestException>();
|
||
}
|
||
|
||
[Fact]
|
||
public async Task ExtractAsync_WhenApiReturns500_ThrowsHttpRequestException()
|
||
{
|
||
// Arrange
|
||
var handler = MockHttpMessageHandler.ReturningStatus(HttpStatusCode.InternalServerError);
|
||
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
||
var client = new SwissQrCodeClient(httpClient, NullLogger<SwissQrCodeClient>.Instance);
|
||
|
||
// Act & Assert
|
||
await client.Invoking(c => c.ExtractAsync(FakePdfBytes()))
|
||
.Should().ThrowAsync<HttpRequestException>();
|
||
}
|
||
}
|