using DocumentService.Application.Common.DTOs; using FluentAssertions; namespace DocumentService.Tests.Live.API; /// /// Live tests for PDF validation endpoints. /// Uses PdfValidationClient — routes are managed by the client, not the test. /// Target: http://172.24.12.39:9393/ /// [Collection("Live API")] public class PdfValidationLiveTests : LiveApiTestBase { // ────────────────────────────────────────────────────────────── // ValidateAsync(Stream) → multipart/form-data → /api/pdf/validation/validate // ────────────────────────────────────────────────────────────── [Fact] public async Task Validate_Stream_ValidPdf_ReturnsMetadata() { using var stream = LoadPdfStream("valid.pdf"); var result = await ValidationClient.ValidateAsync(stream); result.Should().NotBeNull(); result.PageCount.Should().BeGreaterThan(0); result.FileSizeBytes.Should().BeGreaterThan(0); result.PdfVersion.Should().NotBeNullOrEmpty(); result.HasAttachments.Should().BeFalse(); result.AttachmentCount.Should().Be(0); } [Fact] public async Task Validate_Stream_PdfWithAttachments_ReturnsHasAttachmentsTrue() { using var stream = LoadPdfStream("pdfWithMoreThanOneAttachment.pdf"); var result = await ValidationClient.ValidateAsync(stream); result.HasAttachments.Should().BeTrue(); result.AttachmentCount.Should().BeGreaterThan(0); } [Fact] public async Task Validate_Stream_PdfWithSwissQrCode_ReturnsValidResult() { using var stream = LoadPdfStream("pdfWithSwissQRCode.pdf"); var result = await ValidationClient.ValidateAsync(stream); result.Should().NotBeNull(); result.PageCount.Should().BeGreaterThan(0); result.FileSizeBytes.Should().BeGreaterThan(0); } [Fact] public async Task Validate_Stream_EmptyStream_Throws() { using var stream = new MemoryStream(Array.Empty()); var act = async () => await ValidationClient.ValidateAsync(stream); await act.Should().ThrowAsync( "empty file should be rejected with 400"); } [Fact] public async Task Validate_Stream_CorruptedContent_Throws() { // Valid stream shape, but not a PDF byte[] garbage = "THIS IS NOT A PDF FILE"u8.ToArray(); using var stream = new MemoryStream(garbage); var act = async () => await ValidationClient.ValidateAsync(stream); await act.Should().ThrowAsync( "corrupted content should be rejected (500)"); } // ────────────────────────────────────────────────────────────── // ValidateAsync(byte[]) → Base64 JSON → /api/pdf/validation/validate // ────────────────────────────────────────────────────────────── [Fact] public async Task Validate_Bytes_ValidPdf_ReturnsMetadata() { byte[] bytes = LoadPdfBytes("valid.pdf"); var result = await ValidationClient.ValidateAsync(bytes); result.Should().NotBeNull(); result.PageCount.Should().BeGreaterThan(0); result.FileSizeBytes.Should().BeGreaterThan(0); result.PdfVersion.Should().NotBeNullOrEmpty(); } [Fact] public async Task Validate_Bytes_PdfWithAttachments_ReturnsHasAttachmentsTrue() { byte[] bytes = LoadPdfBytes("pdfWithMoreThanOneAttachment.pdf"); var result = await ValidationClient.ValidateAsync(bytes); result.HasAttachments.Should().BeTrue(); result.AttachmentCount.Should().BeGreaterThan(0); } [Fact] public async Task Validate_Bytes_EmptyArray_Throws() { var act = async () => await ValidationClient.ValidateAsync(Array.Empty()); await act.Should().ThrowAsync( "empty byte array encodes to empty Base64, which should be rejected"); } // ────────────────────────────────────────────────────────────── // ValidatePdfAAsync(Stream) → multipart → /api/pdf/validation/validate-pdfa // ────────────────────────────────────────────────────────────── [Fact] public async Task ValidatePdfA_Stream_ValidPdf_ReturnsComplianceFields() { using var stream = LoadPdfStream("valid.pdf"); var result = await ValidationClient.ValidatePdfAAsync(stream); result.Should().NotBeNull(); result.IsValid.Should().BeTrue(); result.PageCount.Should().BeGreaterThan(0); result.PdfVersion.Should().NotBeNullOrEmpty(); result.FileSize.Should().BeGreaterThan(0); result.Encrypted.Should().BeFalse(); // valid.pdf is a regular PDF, not PDF/A result.PdfACompliant.Should().BeFalse(); result.PdfAVersion.Should().BeNullOrEmpty(); } [Fact] public async Task ValidatePdfA_Stream_EncryptedPdf_ReturnsEncryptedTrue_NotCompliant() { using var stream = LoadPdfStream("encryptedPdf.pdf"); var result = await ValidationClient.ValidatePdfAAsync(stream); result.Should().NotBeNull(); result.Encrypted.Should().BeTrue(); result.PdfACompliant.Should().BeFalse("encrypted PDFs cannot be PDF/A compliant"); } [Fact] public async Task ValidatePdfA_Stream_EmptyStream_Throws() { using var stream = new MemoryStream(Array.Empty()); var act = async () => await ValidationClient.ValidatePdfAAsync(stream); await act.Should().ThrowAsync(); } // ────────────────────────────────────────────────────────────── // ValidatePdfAAsync(byte[]) → Base64 JSON → /api/pdf/validation/validate-pdfa // ────────────────────────────────────────────────────────────── [Fact] public async Task ValidatePdfA_Bytes_ValidPdf_ReturnsComplianceFields() { byte[] bytes = LoadPdfBytes("valid.pdf"); var result = await ValidationClient.ValidatePdfAAsync(bytes); result.Should().NotBeNull(); result.IsValid.Should().BeTrue(); result.PdfACompliant.Should().BeFalse(); result.PageCount.Should().BeGreaterThan(0); } [Fact] public async Task ValidatePdfA_Bytes_EncryptedPdf_ReturnsEncryptedTrue() { byte[] bytes = LoadPdfBytes("encryptedPdf.pdf"); var result = await ValidationClient.ValidatePdfAAsync(bytes); result.Encrypted.Should().BeTrue(); result.PdfACompliant.Should().BeFalse(); } [Fact] public async Task ValidatePdfA_Bytes_EmptyArray_Throws() { var act = async () => await ValidationClient.ValidatePdfAAsync(Array.Empty()); await act.Should().ThrowAsync(); } }