Refactor: Rename DocumentOperator to DocumentService
Updated project and solution files to rename and restructure `DocumentOperator` to `DocumentService`. Modified project references in `DocumentService.API.csproj`, `DocumentService.Application.csproj`, and `DocumentService.Infrastructure.csproj` to reflect the new naming convention. Updated `DocumentService.sln` to remove old project references, add new ones, and adjust configuration and nested project mappings accordingly. This change aligns the project structure with the new naming convention.
This commit is contained in:
@@ -0,0 +1,500 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user