Files
DocumentService/DocumentOperator.Tests/Integration/API/PdfOperationsControllerTests.cs
TekH 0e88b349d7 Rebrand project: DocumentOperator to DocumentService
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.
2026-07-30 14:02:56 +02:00

501 lines
17 KiB
C#

using System.Net;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.Json;
using DocumentService.API.Controllers;
using DocumentService.Domain.Models.ValueObjects;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
namespace DocumentService.Tests.Integration.API;
public class PdfOperationsControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public PdfOperationsControllerTests(WebApplicationFactory<Program> factory)
{
_client = factory.CreateClient();
}
private static Stream LoadTestPdfAsStream(string fileName)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = $"DocumentService.Tests.TestData.Pdfs.{fileName}";
return assembly.GetManifestResourceStream(resourceName)
?? throw new FileNotFoundException($"Embedded resource not found: {resourceName}");
}
private static string LoadTestPdfAsBase64(string fileName)
{
using var stream = LoadTestPdfAsStream(fileName);
using var ms = new MemoryStream();
stream.CopyTo(ms);
return Convert.ToBase64String(ms.ToArray());
}
#region Merge Endpoint Tests (existing - keeping for reference)
[Fact]
public async Task MergeFromFiles_ValidPdfs_ReturnsMergedPdf()
{
// Arrange
using var content = new MultipartFormDataContent();
using var pdf1Stream = LoadTestPdfAsStream("valid.pdf");
using var pdf2Stream = LoadTestPdfAsStream("valid.pdf");
var pdf1Content = new StreamContent(pdf1Stream);
var pdf2Content = new StreamContent(pdf2Stream);
pdf1Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
pdf2Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(pdf1Content, "files", "file1.pdf");
content.Add(pdf2Content, "files", "file2.pdf");
// Act
var response = await _client.PostAsync("/api/pdf/operations/merge", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
response.Content.Headers.ContentType?.MediaType.Should().Be("application/pdf");
byte[] mergedPdf = await response.Content.ReadAsByteArrayAsync();
mergedPdf.Should().NotBeEmpty();
mergedPdf.Length.Should().BeGreaterThan(100); // Sanity check
}
[Fact]
public async Task MergeFromBase64_ValidPdfs_ReturnsMergedPdf()
{
// Arrange
string base64Pdf1 = LoadTestPdfAsBase64("valid.pdf");
string base64Pdf2 = LoadTestPdfAsBase64("valid.pdf");
var request = new MergePdfsBase64Request
{
Base64Pdfs = new List<string> { base64Pdf1, base64Pdf2 },
PageRanges = null
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/merge", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
byte[] mergedPdf = await response.Content.ReadAsByteArrayAsync();
mergedPdf.Should().NotBeEmpty();
}
[Fact]
public async Task MergeFromBase64_WithPageRanges_ReturnsMergedPdf()
{
// Arrange
string base64Pdf1 = LoadTestPdfAsBase64("valid.pdf");
string base64Pdf2 = LoadTestPdfAsBase64("valid.pdf");
var request = new MergePdfsBase64Request
{
Base64Pdfs = new List<string> { base64Pdf1, base64Pdf2 },
PageRanges = new List<string?> { "1", "1" } // Only first page from each
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/merge", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
byte[] mergedPdf = await response.Content.ReadAsByteArrayAsync();
mergedPdf.Should().NotBeEmpty();
}
[Fact]
public async Task MergeFromFiles_OnePdf_Returns400()
{
// Arrange
using var content = new MultipartFormDataContent();
using var pdfStream = LoadTestPdfAsStream("valid.pdf");
var pdfContent = new StreamContent(pdfStream);
pdfContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(pdfContent, "files", "file1.pdf");
// Act
var response = await _client.PostAsync("/api/pdf/operations/merge", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
[Fact]
public async Task MergeFromBase64_InvalidBase64_Returns400()
{
// Arrange
var request = new MergePdfsBase64Request
{
Base64Pdfs = new List<string> { "INVALID_BASE64!!!", "ANOTHER_INVALID" }
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/merge", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
[Fact]
public async Task MergeFromBase64_InvalidPageRange_Returns400()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new MergePdfsBase64Request
{
Base64Pdfs = new List<string> { base64Pdf, base64Pdf },
PageRanges = new List<string?> { "999-1000", null } // Exceeds page count
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/merge", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
[Fact]
public async Task MergeFromFiles_CorruptedPdf_Returns500()
{
// Arrange
using var content = new MultipartFormDataContent();
byte[] corruptedData = "NOT A PDF FILE"u8.ToArray();
var corruptedContent = new ByteArrayContent(corruptedData);
corruptedContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
using var validPdfStream = LoadTestPdfAsStream("valid.pdf");
var validContent = new StreamContent(validPdfStream);
validContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(corruptedContent, "files", "corrupted.pdf");
content.Add(validContent, "files", "valid.pdf");
// Act
var response = await _client.PostAsync("/api/pdf/operations/merge", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.InternalServerError);
}
#endregion
#region Annotate Endpoint Tests
[Fact]
public async Task AnnotateFromFile_TextMarkupHighlight_ReturnsAnnotatedPdf()
{
// Arrange
using var content = new MultipartFormDataContent();
using var pdfStream = LoadTestPdfAsStream("valid.pdf");
var pdfContent = new StreamContent(pdfStream);
pdfContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(pdfContent, "file", "test.pdf");
content.Add(new StringContent(AnnotationType.TextMarkup.ToString()), "annotationType");
content.Add(new StringContent("1"), "pageNumber");
content.Add(new StringContent("100"), "x1");
content.Add(new StringContent("100"), "y1");
content.Add(new StringContent("200"), "x2");
content.Add(new StringContent("120"), "y2");
content.Add(new StringContent("Important text"), "content");
content.Add(new StringContent("Test Author"), "author");
content.Add(new StringContent("FFFF00"), "color");
content.Add(new StringContent(TextMarkupStyle.Highlight.ToString()), "textMarkupStyle");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
response.Content.Headers.ContentType?.MediaType.Should().Be("application/pdf");
byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
annotatedPdf.Should().NotBeEmpty();
annotatedPdf.Length.Should().BeGreaterThan(100);
}
[Fact]
public async Task AnnotateFromBase64_FreeText_ReturnsAnnotatedPdf()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new AddAnnotationBase64Command
{
Base64Pdf = base64Pdf,
AnnotationType = AnnotationType.FreeText,
PageNumber = 1,
X1 = 50,
Y1 = 50,
X2 = 150,
Y2 = 100,
Content = "Free text annotation",
Author = "John Doe",
Color = "FF0000"
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
annotatedPdf.Should().NotBeEmpty();
}
[Fact]
public async Task AnnotateFromBase64_StickyNote_ReturnsAnnotatedPdf()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new AddAnnotationBase64Command
{
Base64Pdf = base64Pdf,
AnnotationType = AnnotationType.StickyNote,
PageNumber = 1,
X1 = 300,
Y1 = 300,
X2 = 320,
Y2 = 320,
Content = "Please review this section",
Author = "Reviewer"
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
annotatedPdf.Should().NotBeEmpty();
}
[Fact]
public async Task AnnotateFromFile_Circle_ReturnsAnnotatedPdf()
{
// Arrange
using var content = new MultipartFormDataContent();
using var pdfStream = LoadTestPdfAsStream("valid.pdf");
var pdfContent = new StreamContent(pdfStream);
pdfContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Add(pdfContent, "file", "test.pdf");
content.Add(new StringContent(AnnotationType.Circle.ToString()), "annotationType");
content.Add(new StringContent("1"), "pageNumber");
content.Add(new StringContent("100"), "x1");
content.Add(new StringContent("200"), "y1");
content.Add(new StringContent("200"), "x2");
content.Add(new StringContent("300"), "y2");
content.Add(new StringContent("Circle annotation"), "content");
content.Add(new StringContent("00FF00"), "color");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
annotatedPdf.Should().NotBeEmpty();
}
[Fact]
public async Task AnnotateFromBase64_Square_ReturnsAnnotatedPdf()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new AddAnnotationBase64Command
{
Base64Pdf = base64Pdf,
AnnotationType = AnnotationType.Square,
PageNumber = 1,
X1 = 250,
Y1 = 250,
X2 = 350,
Y2 = 350,
Color = "0000FF"
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
byte[] annotatedPdf = await response.Content.ReadAsByteArrayAsync();
annotatedPdf.Should().NotBeEmpty();
}
[Fact]
public async Task AnnotateFromBase64_InvalidBase64_Returns400()
{
// Arrange
var request = new AddAnnotationBase64Command
{
Base64Pdf = "INVALID_BASE64!!!",
AnnotationType = AnnotationType.Circle,
PageNumber = 1,
X1 = 0,
Y1 = 0,
X2 = 100,
Y2 = 100
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
[Fact]
public async Task AnnotateFromBase64_InvalidPageNumber_Returns400()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new AddAnnotationBase64Command
{
Base64Pdf = base64Pdf,
AnnotationType = AnnotationType.FreeText,
PageNumber = 999, // Exceeds page count
X1 = 0,
Y1 = 0,
X2 = 100,
Y2 = 100,
Content = "Test"
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
[Fact]
public async Task AnnotateFromBase64_FreeTextWithoutContent_Returns400()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new AddAnnotationBase64Command
{
Base64Pdf = base64Pdf,
AnnotationType = AnnotationType.FreeText,
PageNumber = 1,
X1 = 0,
Y1 = 0,
X2 = 100,
Y2 = 100
// Missing required Content
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
[Fact]
public async Task AnnotateFromBase64_TextMarkupWithoutStyle_Returns400()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new AddAnnotationBase64Command
{
Base64Pdf = base64Pdf,
AnnotationType = AnnotationType.TextMarkup,
PageNumber = 1,
X1 = 0,
Y1 = 0,
X2 = 100,
Y2 = 100
// Missing required TextMarkupStyle
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
[Fact]
public async Task AnnotateFromBase64_InvalidColorFormat_Returns400()
{
// Arrange
string base64Pdf = LoadTestPdfAsBase64("valid.pdf");
var request = new AddAnnotationBase64Command
{
Base64Pdf = base64Pdf,
AnnotationType = AnnotationType.Circle,
PageNumber = 1,
X1 = 0,
Y1 = 0,
X2 = 100,
Y2 = 100,
Color = "INVALID" // Invalid hex format
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/pdf/operations/annotate", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
}
#endregion
}