test: Add unit tests for DocumentService.Client
This commit is contained in:
236
DocumentOperator.Tests/Unit/Client/PdfOperationsClientTests.cs
Normal file
236
DocumentOperator.Tests/Unit/Client/PdfOperationsClientTests.cs
Normal file
@@ -0,0 +1,236 @@
|
||||
using DocumentService.Client.Clients;
|
||||
using DocumentService.Client.Interfaces;
|
||||
using DocumentService.Client.Models.Requests;
|
||||
using DocumentService.Client.Models.ValueObjects;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DocumentService.Tests.Unit.Client;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="PdfOperationsClient"/>.
|
||||
/// All tests use a fake <see cref="MockHttpMessageHandler"/> — no real HTTP calls are made.
|
||||
/// </summary>
|
||||
public class PdfOperationsClientTests
|
||||
{
|
||||
// ?? helpers ?????????????????????????????????????????????????????????????
|
||||
|
||||
private static (PdfOperationsClient client, MockHttpMessageHandler handler) BuildBytes(byte[] bytes = null!)
|
||||
{
|
||||
var handler = MockHttpMessageHandler.ReturningBytes(bytes ?? "merged-pdf"u8.ToArray(), "application/pdf");
|
||||
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
||||
var client = new PdfOperationsClient(httpClient, NullLogger<PdfOperationsClient>.Instance);
|
||||
return (client, handler);
|
||||
}
|
||||
|
||||
private static byte[] FakePdfBytes() => "fake-pdf-content"u8.ToArray();
|
||||
|
||||
private static AddAnnotationBase64Request FakeAnnotationRequest() => new()
|
||||
{
|
||||
Base64Pdf = string.Empty,
|
||||
AnnotationType = AnnotationType.TextMarkup,
|
||||
PageNumber = 1,
|
||||
X1 = 10, Y1 = 20, Width = 100, Height = 30,
|
||||
Color = "FFFF00",
|
||||
TextMarkupStyle = TextMarkupStyle.Highlight,
|
||||
Origin = AnnotationOrigin.TopLeft
|
||||
};
|
||||
|
||||
private static AddStampBase64Request FakeStampRequest() => new()
|
||||
{
|
||||
Base64Pdf = string.Empty,
|
||||
StampType = StampType.Text,
|
||||
X = 100, Y = 50,
|
||||
Text = "CONFIDENTIAL",
|
||||
FontSize = 24,
|
||||
Color = "FF0000",
|
||||
Opacity = 0.5,
|
||||
Placement = StampPlacement.Foreground,
|
||||
Origin = AnnotationOrigin.BottomLeft
|
||||
};
|
||||
|
||||
// ?? MergeAsync (Streams) ?????????????????????????????????????????????????
|
||||
|
||||
[Fact]
|
||||
public async Task MergeAsync_Streams_SendsMultipartWithAllFiles()
|
||||
{
|
||||
// Arrange
|
||||
var (client, handler) = BuildBytes();
|
||||
var streams = new List<Stream>
|
||||
{
|
||||
new MemoryStream(FakePdfBytes()),
|
||||
new MemoryStream(FakePdfBytes())
|
||||
};
|
||||
|
||||
// Act
|
||||
using var result = await client.MergeAsync(streams);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/operations/merge");
|
||||
handler.LastRequest.Content.Should().BeOfType<MultipartFormDataContent>();
|
||||
|
||||
foreach (var s in streams) s.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MergeAsync_Streams_ReturnsMergedPdfStream()
|
||||
{
|
||||
// Arrange
|
||||
var expectedBytes = "merged-content"u8.ToArray();
|
||||
var (client, _) = BuildBytes(expectedBytes);
|
||||
|
||||
// Act
|
||||
using var result = await client.MergeAsync(new[] { new MemoryStream(FakePdfBytes()), new MemoryStream(FakePdfBytes()) });
|
||||
var actualBytes = await result.ReadAllBytesAsync();
|
||||
|
||||
// Assert
|
||||
actualBytes.Should().BeEquivalentTo(expectedBytes);
|
||||
}
|
||||
|
||||
// ?? MergeAsync (byte[][]) ????????????????????????????????????????????????
|
||||
|
||||
[Fact]
|
||||
public async Task MergeAsync_ByteArrays_SendsJsonWithBase64List()
|
||||
{
|
||||
// Arrange
|
||||
var (client, handler) = BuildBytes();
|
||||
|
||||
// Act
|
||||
using var result = await client.MergeAsync(new[] { FakePdfBytes(), FakePdfBytes() });
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Content.Should().NotBeNull();
|
||||
handler.LastRequest.Content!.Headers.ContentType!.MediaType.Should().Be("application/json");
|
||||
var body = await handler.LastRequest.Content!.ReadAsStringAsync();
|
||||
var doc = JsonDocument.Parse(body);
|
||||
doc.RootElement.GetProperty("base64Pdfs").GetArrayLength().Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MergeAsync_ByteArrays_WithPageRanges_IncludesPageRangesInJson()
|
||||
{
|
||||
// Arrange
|
||||
var (client, handler) = BuildBytes();
|
||||
var pageRanges = new List<string?> { "1-2", null };
|
||||
|
||||
// Act
|
||||
await client.MergeAsync(new[] { FakePdfBytes(), FakePdfBytes() }, pageRanges);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Content.Should().NotBeNull();
|
||||
var body = await handler.LastRequest!.Content!.ReadAsStringAsync();
|
||||
var doc = JsonDocument.Parse(body);
|
||||
doc.RootElement.GetProperty("pageRanges").GetArrayLength().Should().Be(2);
|
||||
}
|
||||
|
||||
// ?? AnnotateAsync (Stream) ????????????????????????????????????????????????
|
||||
|
||||
[Fact]
|
||||
public async Task AnnotateAsync_Stream_SendsMultipartWithAnnotationFields()
|
||||
{
|
||||
// Arrange
|
||||
var (client, handler) = BuildBytes();
|
||||
var request = FakeAnnotationRequest();
|
||||
|
||||
// Act
|
||||
using var result = await client.AnnotateAsync(new MemoryStream(FakePdfBytes()), request);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/operations/annotate");
|
||||
handler.LastRequest.Content.Should().BeOfType<MultipartFormDataContent>();
|
||||
}
|
||||
|
||||
// ?? AnnotateAsync (byte[]) ????????????????????????????????????????????????
|
||||
|
||||
[Fact]
|
||||
public async Task AnnotateAsync_Bytes_SendsJsonWithBase64Pdf()
|
||||
{
|
||||
// Arrange
|
||||
var (client, handler) = BuildBytes();
|
||||
var request = FakeAnnotationRequest();
|
||||
|
||||
// Act
|
||||
await client.AnnotateAsync(FakePdfBytes(), request);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Content.Should().NotBeNull();
|
||||
handler.LastRequest.Content!.Headers.ContentType!.MediaType.Should().Be("application/json");
|
||||
var body = await handler.LastRequest.Content!.ReadAsStringAsync();
|
||||
var doc = JsonDocument.Parse(body);
|
||||
doc.RootElement.GetProperty("base64Pdf").GetString().Should().NotBeNullOrEmpty();
|
||||
// annotationType serializes as integer by default (TextMarkup = 0)
|
||||
doc.RootElement.GetProperty("annotationType").GetInt32().Should().Be((int)AnnotationType.TextMarkup);
|
||||
}
|
||||
|
||||
// ?? StampAsync (Stream) ???????????????????????????????????????????????????
|
||||
|
||||
[Fact]
|
||||
public async Task StampAsync_Stream_SendsMultipartWithStampFields()
|
||||
{
|
||||
// Arrange
|
||||
var (client, handler) = BuildBytes();
|
||||
var request = FakeStampRequest();
|
||||
|
||||
// Act
|
||||
using var result = await client.StampAsync(new MemoryStream(FakePdfBytes()), request);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/operations/stamp");
|
||||
handler.LastRequest.Content.Should().BeOfType<MultipartFormDataContent>();
|
||||
}
|
||||
|
||||
// ?? StampAsync (byte[]) ???????????????????????????????????????????????????
|
||||
|
||||
[Fact]
|
||||
public async Task StampAsync_Bytes_SendsJsonWithBase64Pdf()
|
||||
{
|
||||
// Arrange
|
||||
var (client, handler) = BuildBytes();
|
||||
var request = FakeStampRequest();
|
||||
|
||||
// Act
|
||||
await client.StampAsync(FakePdfBytes(), request);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Content.Should().NotBeNull();
|
||||
handler.LastRequest.Content!.Headers.ContentType!.MediaType.Should().Be("application/json");
|
||||
var body = await handler.LastRequest.Content!.ReadAsStringAsync();
|
||||
var doc = JsonDocument.Parse(body);
|
||||
doc.RootElement.GetProperty("base64Pdf").GetString().Should().NotBeNullOrEmpty();
|
||||
// stampType serializes as integer by default (Text = 0)
|
||||
doc.RootElement.GetProperty("stampType").GetInt32().Should().Be((int)StampType.Text);
|
||||
}
|
||||
|
||||
// ?? HTTP error propagation ???????????????????????????????????????????????
|
||||
|
||||
[Fact]
|
||||
public async Task MergeAsync_WhenApiReturns400_ThrowsHttpRequestException()
|
||||
{
|
||||
// Arrange
|
||||
var handler = MockHttpMessageHandler.ReturningStatus(HttpStatusCode.BadRequest);
|
||||
var httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") };
|
||||
var client = new PdfOperationsClient(httpClient, NullLogger<PdfOperationsClient>.Instance);
|
||||
|
||||
// Act & Assert
|
||||
await client.Invoking(c => c.MergeAsync(new[] { new MemoryStream(FakePdfBytes()), new MemoryStream(FakePdfBytes()) }))
|
||||
.Should().ThrowAsync<HttpRequestException>();
|
||||
}
|
||||
}
|
||||
|
||||
// ?? local helper extension ???????????????????????????????????????????????????
|
||||
|
||||
file static class StreamHelper
|
||||
{
|
||||
public static async Task<byte[]> ReadAllBytesAsync(this Stream stream)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
await stream.CopyToAsync(ms);
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user