200 lines
7.4 KiB
C#
200 lines
7.4 KiB
C#
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="ZugferdClient"/>.
|
|
/// All tests use a fake <see cref="MockHttpMessageHandler"/> — no real HTTP calls are made.
|
|
/// </summary>
|
|
public class ZugferdClientTests
|
|
{
|
|
// ?? helpers ?????????????????????????????????????????????????????????????
|
|
|
|
private static (ZugferdClient client, MockHttpMessageHandler handler) BuildJson<T>(T body)
|
|
{
|
|
var handler = MockHttpMessageHandler.ReturningJson(body);
|
|
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
|
var client = new ZugferdClient(httpClient, NullLogger<ZugferdClient>.Instance);
|
|
return (client, handler);
|
|
}
|
|
|
|
private static (ZugferdClient client, MockHttpMessageHandler handler) BuildBytes(byte[] bytes, string mediaType = "application/xml")
|
|
{
|
|
var handler = MockHttpMessageHandler.ReturningBytes(bytes, mediaType);
|
|
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
|
var client = new ZugferdClient(httpClient, NullLogger<ZugferdClient>.Instance);
|
|
return (client, handler);
|
|
}
|
|
|
|
private static byte[] FakePdfBytes() => "fake-pdf-content"u8.ToArray();
|
|
private static byte[] FakeXmlBytes() => "<invoice>test</invoice>"u8.ToArray();
|
|
|
|
// ?? HasZugferdAsync (Stream) ?????????????????????????????????????????????
|
|
|
|
[Fact]
|
|
public async Task HasZugferdAsync_Stream_WhenZugferdPresent_ReturnsTrue()
|
|
{
|
|
// Arrange
|
|
var expected = new ZugferdCheckResult { HasZugferd = true, Version = "2.1", Profile = "EN 16931" };
|
|
var (client, handler) = BuildJson(expected);
|
|
|
|
// Act
|
|
var result = await client.HasZugferdAsync(new MemoryStream(FakePdfBytes()));
|
|
|
|
// Assert
|
|
result.HasZugferd.Should().BeTrue();
|
|
result.Version.Should().Be("2.1");
|
|
result.Profile.Should().Be("EN 16931");
|
|
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/zugferd/has-zugferd");
|
|
handler.LastRequest.Content.Should().BeOfType<MultipartFormDataContent>();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task HasZugferdAsync_Stream_WhenNoZugferd_ReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var expected = new ZugferdCheckResult { HasZugferd = false };
|
|
var (client, _) = BuildJson(expected);
|
|
|
|
// Act
|
|
var result = await client.HasZugferdAsync(new MemoryStream(FakePdfBytes()));
|
|
|
|
// Assert
|
|
result.HasZugferd.Should().BeFalse();
|
|
result.Version.Should().BeNull();
|
|
}
|
|
|
|
// ?? HasZugferdAsync (byte[]) ?????????????????????????????????????????????
|
|
|
|
[Fact]
|
|
public async Task HasZugferdAsync_Bytes_SendsJsonWithBase64()
|
|
{
|
|
// Arrange
|
|
var expected = new ZugferdCheckResult { HasZugferd = true };
|
|
var (client, handler) = BuildJson(expected);
|
|
|
|
// Act
|
|
await client.HasZugferdAsync(FakePdfBytes());
|
|
|
|
// 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();
|
|
}
|
|
|
|
// ?? ExtractZugferdAsync (Stream) — raw XML stream ?????????????????????????
|
|
|
|
[Fact]
|
|
public async Task ExtractZugferdAsync_Stream_SendsMultipartWithAsFileTrue()
|
|
{
|
|
// Arrange
|
|
var (client, handler) = BuildBytes(FakeXmlBytes());
|
|
|
|
// Act
|
|
using var result = await client.ExtractZugferdAsync(new MemoryStream(FakePdfBytes()));
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/zugferd/extract?asFile=true");
|
|
handler.LastRequest.Content.Should().BeOfType<MultipartFormDataContent>();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExtractZugferdAsync_Stream_ReturnsXmlContent()
|
|
{
|
|
// Arrange
|
|
var xmlBytes = "<root><invoice/></root>"u8.ToArray();
|
|
var (client, _) = BuildBytes(xmlBytes);
|
|
|
|
// Act
|
|
using var result = await client.ExtractZugferdAsync(new MemoryStream(FakePdfBytes()));
|
|
var content = await new StreamReader(result).ReadToEndAsync();
|
|
|
|
// Assert
|
|
content.Should().Be("<root><invoice/></root>");
|
|
}
|
|
|
|
// ?? ExtractZugferdAsync (byte[]) ?????????????????????????????????????????
|
|
|
|
[Fact]
|
|
public async Task ExtractZugferdAsync_Bytes_SendsJsonWithFormatFile()
|
|
{
|
|
// Arrange
|
|
var (client, handler) = BuildBytes(FakeXmlBytes());
|
|
|
|
// Act
|
|
using var result = await client.ExtractZugferdAsync(FakePdfBytes());
|
|
|
|
// Assert
|
|
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/zugferd/extract?format=file");
|
|
handler.LastRequest.Content.Should().NotBeNull();
|
|
handler.LastRequest.Content!.Headers.ContentType!.MediaType.Should().Be("application/json");
|
|
}
|
|
|
|
// ?? ExtractZugferdAsResultAsync (Stream) ?????????????????????????????????
|
|
|
|
[Fact]
|
|
public async Task ExtractZugferdAsResultAsync_Stream_ReturnsStructuredResult()
|
|
{
|
|
// Arrange
|
|
var expected = new ZugferdExtractionResult
|
|
{
|
|
FileName = "factur-x.xml",
|
|
XmlContent = "<invoice/>",
|
|
Version = "2.1",
|
|
Profile = "EN 16931"
|
|
};
|
|
var (client, handler) = BuildJson(expected);
|
|
|
|
// Act
|
|
var result = await client.ExtractZugferdAsResultAsync(new MemoryStream(FakePdfBytes()));
|
|
|
|
// Assert
|
|
result.FileName.Should().Be("factur-x.xml");
|
|
result.XmlContent.Should().Be("<invoice/>");
|
|
result.Version.Should().Be("2.1");
|
|
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/zugferd/extract?asFile=false");
|
|
}
|
|
|
|
// ?? ExtractZugferdAsResultAsync (byte[]) ?????????????????????????????????
|
|
|
|
[Fact]
|
|
public async Task ExtractZugferdAsResultAsync_Bytes_SendsJsonWithFormatJson()
|
|
{
|
|
// Arrange
|
|
var expected = new ZugferdExtractionResult { FileName = "zugferd.xml", XmlContent = "<x/>" };
|
|
var (client, handler) = BuildJson(expected);
|
|
|
|
// Act
|
|
await client.ExtractZugferdAsResultAsync(FakePdfBytes());
|
|
|
|
// Assert
|
|
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/zugferd/extract?format=json");
|
|
handler.LastRequest.Content.Should().NotBeNull();
|
|
handler.LastRequest.Content!.Headers.ContentType!.MediaType.Should().Be("application/json");
|
|
}
|
|
|
|
// ?? HTTP error propagation ???????????????????????????????????????????????
|
|
|
|
[Fact]
|
|
public async Task HasZugferdAsync_WhenApiReturns400_ThrowsHttpRequestException()
|
|
{
|
|
// Arrange
|
|
var handler = MockHttpMessageHandler.ReturningStatus(HttpStatusCode.BadRequest);
|
|
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
|
var client = new ZugferdClient(httpClient, NullLogger<ZugferdClient>.Instance);
|
|
|
|
// Act & Assert
|
|
await client.Invoking(c => c.HasZugferdAsync(new MemoryStream(FakePdfBytes())))
|
|
.Should().ThrowAsync<HttpRequestException>();
|
|
}
|
|
}
|