using DocumentService.Application.Common.DTOs;
using FluentAssertions;
namespace DocumentService.Tests.Live.API;
///
/// Live tests for Swiss QR Code extraction endpoint.
/// Uses SwissQrCodeClient — routes managed by the client.
/// Target: http://172.24.12.39:9393/
///
[Collection("Live API")]
public class SwissQrCodeLiveTests : LiveApiTestBase
{
// ──────────────────────────────────────────────────────────────
// ExtractAsync(Stream) → multipart → /api/pdf/qr-code/extract-swiss
// ──────────────────────────────────────────────────────────────
[Fact]
public async Task Extract_Stream_PdfWithQrCode_ReturnsBillDetails()
{
using var stream = LoadPdfStream("pdfWithSwissQRCode.pdf");
var result = await QrCodeClient.ExtractAsync(stream);
result.Should().NotBeNull();
result.Bill.Should().NotBeNull("bill data must be extracted");
result.RawLines.Should().NotBeEmpty("raw QR payload lines must be present");
// Swiss QR Bill Standard 2.0 payload always starts with "SPC"
result.RawLines.Should().Contain(line => line == "SPC",
"first SPC line is mandated by Swiss QR Bill Standard 2.0");
}
[Fact]
public async Task Extract_Stream_PdfWithQrCode_BillHasMandatoryFields()
{
using var stream = LoadPdfStream("pdfWithSwissQRCode.pdf");
var result = await QrCodeClient.ExtractAsync(stream);
var bill = result.Bill;
bill.Should().NotBeNull();
bill!.Account.Should().NotBeNullOrEmpty("IBAN/QR-IBAN is mandatory per standard");
bill.Creditor.Should().NotBeNull("Creditor is mandatory");
bill.Creditor!.Name.Should().NotBeNullOrEmpty("Creditor name is mandatory");
}
[Fact]
public async Task Extract_Stream_PdfWithoutQrCode_Throws404()
{
// valid.pdf has no QR code
using var stream = LoadPdfStream("valid.pdf");
var act = async () => await QrCodeClient.ExtractAsync(stream);
// Client calls EnsureSuccessStatusCode → HttpRequestException on 404
await act.Should().ThrowAsync(
"PDF without QR code must return 404");
}
[Fact]
public async Task Extract_Stream_EmptyStream_Throws()
{
using var stream = new MemoryStream(Array.Empty());
var act = async () => await QrCodeClient.ExtractAsync(stream);
await act.Should().ThrowAsync();
}
[Fact]
public async Task Extract_Stream_WithRawFlag_ReturnsRawLines()
{
using var stream = LoadPdfStream("pdfWithSwissQRCode.pdf");
// raw=true → API returns full unprocessed payload lines
var result = await QrCodeClient.ExtractAsync(stream, raw: true);
result.Should().NotBeNull();
result.RawLines.Should().NotBeEmpty();
}
// ──────────────────────────────────────────────────────────────
// ExtractAsync(byte[]) → Base64 JSON → /api/pdf/qr-code/extract-swiss
// ──────────────────────────────────────────────────────────────
[Fact]
public async Task Extract_Bytes_PdfWithQrCode_ReturnsBillDetails()
{
byte[] bytes = LoadPdfBytes("pdfWithSwissQRCode.pdf");
var result = await QrCodeClient.ExtractAsync(bytes);
result.Should().NotBeNull();
result.Bill.Should().NotBeNull();
result.RawLines.Should().NotBeEmpty();
}
[Fact]
public async Task Extract_Bytes_PdfWithQrCode_BillHasMandatoryFields()
{
byte[] bytes = LoadPdfBytes("pdfWithSwissQRCode.pdf");
var result = await QrCodeClient.ExtractAsync(bytes);
result.Bill!.Account.Should().NotBeNullOrEmpty();
result.Bill.Creditor.Should().NotBeNull();
result.Bill.Creditor!.Name.Should().NotBeNullOrEmpty();
}
[Fact]
public async Task Extract_Bytes_PdfWithoutQrCode_Throws404()
{
byte[] bytes = LoadPdfBytes("valid.pdf");
var act = async () => await QrCodeClient.ExtractAsync(bytes);
await act.Should().ThrowAsync(
"PDF without QR code must return 404");
}
[Fact]
public async Task Extract_Bytes_EmptyArray_Throws()
{
var act = async () => await QrCodeClient.ExtractAsync(Array.Empty());
await act.Should().ThrowAsync();
}
}