This commit implements a complete rebranding of the project: - Updated all namespaces from `DocumentOperator` to `DocumentService`. - Renamed file paths, embedded resources, and test data references. - Updated configuration keys, logging paths, and Redis instance names. - Revised documentation to reflect the new project name. - Modified project and solution files to align with the new structure. - Updated class names, DTOs, commands, queries, and handlers. - Adjusted middleware, controllers, and API endpoints. - Updated Swagger metadata and API titles to `DocumentService API`. - Refactored test namespaces, resource paths, and embedded resources. - Updated build and deployment configurations for the new name. - Replaced all references to `DocumentOperator` in comments and literals. These changes ensure consistency across the codebase and documentation.
215 lines
7.0 KiB
C#
215 lines
7.0 KiB
C#
using AutoMapper;
|
|
using DocumentService.Application.Common.DTOs;
|
|
using DocumentService.Application.Common.Interfaces;
|
|
using DocumentService.Application.ValidatePdfA.Queries;
|
|
using DocumentService.Domain.Common.Exceptions;
|
|
|
|
using FluentAssertions;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace DocumentService.Tests.Unit.Application.Features.ValidatePdfA;
|
|
|
|
public class ValidatePdfAQueryHandlerTests
|
|
{
|
|
private readonly Mock<IPdfProcessor> _mockPdfProcessor;
|
|
private readonly Mock<IMapper> _mockMapper;
|
|
private readonly ValidatePdfAQueryHandler _handler;
|
|
|
|
public ValidatePdfAQueryHandlerTests()
|
|
{
|
|
_mockPdfProcessor = new Mock<IPdfProcessor>();
|
|
_mockMapper = new Mock<IMapper>();
|
|
_handler = new ValidatePdfAQueryHandler(_mockPdfProcessor.Object, _mockMapper.Object);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_ValidPdfA_ReturnsPdfAMetadata()
|
|
{
|
|
// Arrange
|
|
var pdfBytes = "%PDF"u8.ToArray(); // "%PDF"
|
|
var query = new ValidatePdfAQuery { PdfStream = new MemoryStream(pdfBytes) };
|
|
|
|
var domainMetadata = new PdfAMetadata(
|
|
isValid: true,
|
|
pdfVersion: "1.7",
|
|
pageCount: 3,
|
|
fileSizeBytes: 2048,
|
|
encrypted: false,
|
|
pdfaVersion: "PDF/A-3b",
|
|
pdfaCompliant: true,
|
|
errors: [],
|
|
warnings: []
|
|
);
|
|
|
|
var expectedDto = new PdfAValidationResult
|
|
{
|
|
IsValid = true,
|
|
PdfVersion = "1.7",
|
|
PageCount = 3,
|
|
FileSize = 2048,
|
|
Encrypted = false,
|
|
PdfAVersion = "PDF/A-3b",
|
|
PdfACompliant = true,
|
|
Errors = new List<string>(),
|
|
Warnings = new List<string>()
|
|
};
|
|
|
|
_mockPdfProcessor
|
|
.Setup(x => x.ValidatePdfAAsync(It.IsAny<Stream>()))
|
|
.ReturnsAsync(domainMetadata);
|
|
|
|
_mockMapper
|
|
.Setup(x => x.Map<PdfAValidationResult>(domainMetadata))
|
|
.Returns(expectedDto);
|
|
|
|
// Act
|
|
var result = await _handler.Handle(query, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.IsValid.Should().BeTrue();
|
|
result.PageCount.Should().Be(3);
|
|
result.PdfVersion.Should().Be("1.7");
|
|
result.PdfAVersion.Should().Be("PDF/A-3b");
|
|
result.PdfACompliant.Should().BeTrue();
|
|
result.Encrypted.Should().BeFalse();
|
|
result.Errors.Should().BeEmpty();
|
|
result.Warnings.Should().BeEmpty();
|
|
|
|
_mockPdfProcessor.Verify(x => x.ValidatePdfAAsync(It.IsAny<Stream>()), Times.Once);
|
|
_mockMapper.Verify(x => x.Map<PdfAValidationResult>(domainMetadata), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_NonCompliantPdfA_ReturnsErrorsAndWarnings()
|
|
{
|
|
// Arrange
|
|
var pdfBytes = new byte[] { 0x25, 0x50, 0x44, 0x46 }; // "%PDF"
|
|
var query = new ValidatePdfAQuery { PdfStream = new MemoryStream(pdfBytes) };
|
|
|
|
var errors = new List<string> { "Missing XMP metadata", "Invalid color space" };
|
|
var warnings = new List<string> { "Embedded font not subset" };
|
|
|
|
var domainMetadata = new PdfAMetadata(
|
|
isValid: false,
|
|
pdfVersion: "1.4",
|
|
pageCount: 2,
|
|
fileSizeBytes: 1024,
|
|
encrypted: false,
|
|
pdfaVersion: null,
|
|
pdfaCompliant: false,
|
|
errors: errors,
|
|
warnings: warnings
|
|
);
|
|
|
|
var expectedDto = new PdfAValidationResult
|
|
{
|
|
IsValid = false,
|
|
PdfVersion = "1.4",
|
|
PageCount = 2,
|
|
FileSize = 1024,
|
|
Encrypted = false,
|
|
PdfAVersion = null,
|
|
PdfACompliant = false,
|
|
Errors = errors,
|
|
Warnings = warnings
|
|
};
|
|
|
|
_mockPdfProcessor
|
|
.Setup(x => x.ValidatePdfAAsync(It.IsAny<Stream>()))
|
|
.ReturnsAsync(domainMetadata);
|
|
|
|
_mockMapper
|
|
.Setup(x => x.Map<PdfAValidationResult>(domainMetadata))
|
|
.Returns(expectedDto);
|
|
|
|
// Act
|
|
var result = await _handler.Handle(query, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.IsValid.Should().BeFalse();
|
|
result.PdfACompliant.Should().BeFalse();
|
|
result.PdfAVersion.Should().BeNull();
|
|
result.Errors.Should().HaveCount(2);
|
|
result.Errors.Should().Contain("Missing XMP metadata");
|
|
result.Warnings.Should().HaveCount(1);
|
|
|
|
_mockPdfProcessor.Verify(x => x.ValidatePdfAAsync(It.IsAny<Stream>()), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_EncryptedPdf_ReturnsEncryptedFlag()
|
|
{
|
|
// Arrange
|
|
var pdfBytes = new byte[] { 0x25, 0x50, 0x44, 0x46 }; // "%PDF"
|
|
var query = new ValidatePdfAQuery { PdfStream = new MemoryStream(pdfBytes) };
|
|
|
|
var domainMetadata = new PdfAMetadata(
|
|
isValid: true,
|
|
pdfVersion: "1.7",
|
|
pageCount: 1,
|
|
fileSizeBytes: 512,
|
|
encrypted: true,
|
|
pdfaVersion: null,
|
|
pdfaCompliant: false,
|
|
errors: new List<string> { "Encrypted PDFs cannot be PDF/A compliant" },
|
|
warnings: new List<string>()
|
|
);
|
|
|
|
var expectedDto = new PdfAValidationResult
|
|
{
|
|
IsValid = true,
|
|
PdfVersion = "1.7",
|
|
PageCount = 1,
|
|
FileSize = 512,
|
|
Encrypted = true,
|
|
PdfAVersion = null,
|
|
PdfACompliant = false,
|
|
Errors = new List<string> { "Encrypted PDFs cannot be PDF/A compliant" },
|
|
Warnings = new List<string>()
|
|
};
|
|
|
|
_mockPdfProcessor
|
|
.Setup(x => x.ValidatePdfAAsync(It.IsAny<Stream>()))
|
|
.ReturnsAsync(domainMetadata);
|
|
|
|
_mockMapper
|
|
.Setup(x => x.Map<PdfAValidationResult>(domainMetadata))
|
|
.Returns(expectedDto);
|
|
|
|
// Act
|
|
var result = await _handler.Handle(query, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Encrypted.Should().BeTrue();
|
|
result.PdfACompliant.Should().BeFalse();
|
|
result.Errors.Should().Contain("Encrypted PDFs cannot be PDF/A compliant");
|
|
|
|
_mockPdfProcessor.Verify(x => x.ValidatePdfAAsync(It.IsAny<Stream>()), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_PdfProcessorThrowsException_PropagatesException()
|
|
{
|
|
// Arrange
|
|
var pdfBytes = new byte[] { 0x25, 0x50, 0x44, 0x46 }; // "%PDF"
|
|
var query = new ValidatePdfAQuery { PdfStream = new MemoryStream(pdfBytes) };
|
|
|
|
_mockPdfProcessor
|
|
.Setup(x => x.ValidatePdfAAsync(It.IsAny<Stream>()))
|
|
.ThrowsAsync(new BadRequestException("Invalid PDF format"));
|
|
|
|
// Act & Assert
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => _handler.Handle(query, CancellationToken.None)
|
|
);
|
|
|
|
exception.Message.Should().Be("Invalid PDF format");
|
|
_mockPdfProcessor.Verify(x => x.ValidatePdfAAsync(It.IsAny<Stream>()), Times.Once);
|
|
}
|
|
}
|
|
|