Files
jobtrackingapp/JobTrackerApi.Tests/CvExportRevisionTests.cs
T
2026-10-27 07:37:03 +01:00

96 lines
5.1 KiB
C#

using System.Security.Claims;
using System.Text.Json;
using JobTrackerApi.Controllers;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using JobTrackerApi.Tests.TestSupport;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Moq;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class CvExportRevisionTests
{
[Fact]
public async Task Explicit_blank_export_is_rejected_before_pdf_allocation()
{
var current = new Mock<ICurrentUserService>();
current.SetupGet(x => x.UserId).Returns("owner");
await using var db = new JobTrackerContext(new DbContextOptionsBuilder<JobTrackerContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options, current.Object);
var variants = new CvVariantService(db, new CareerProfileService(db), new ThemedCvRenderer());
var settings = CvVariantSettingsJson.Deserialize("{\"sectionsExplicit\":true,\"includeProfileContact\":false,\"sections\":[]}");
var cv = await variants.CreateAsync("owner", "Blank", null, settings, default);
var user = new ApplicationUser { Id = "owner", FirstName = "Inherited name" };
var users = TestHostFactory.CreateUserManager(user);
users.Setup(x => x.GetUserAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(user);
var pdf = new Mock<ICvPdfExporter>(MockBehavior.Strict);
var controller = new CvVariantController(users.Object, variants, pdf.Object, Mock.Of<ISummarizerService>())
{ ControllerContext = new() { HttpContext = new DefaultHttpContext() } };
var result = Assert.IsType<BadRequestObjectResult>(await controller.ExportPdf(cv.Id, default, 1));
Assert.Equal("cv_empty_content", JsonSerializer.SerializeToElement(result.Value).GetProperty("code").GetString());
pdf.VerifyNoOtherCalls();
}
[Theory]
[InlineData(1, "owner", 409)]
[InlineData(0, "owner", 409)]
[InlineData(1, "other", 404)]
[InlineData(2, "other", 404)]
[InlineData(2, "owner", 200)]
[InlineData(null, "owner", 200)]
public async Task Export_checks_the_owned_render_revision_before_allocating_a_pdf(int? expectedVersion, string caller, int status)
{
await using var connection = new SqliteConnection("Data Source=:memory:");
await connection.OpenAsync();
var current = new Mock<ICurrentUserService>();
current.SetupGet(x => x.UserId).Returns("owner");
var options = new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(connection).Options;
await using var seed = new JobTrackerContext(options, current.Object);
await seed.Database.EnsureCreatedAsync();
var variants = new CvVariantService(seed, new CareerProfileService(seed), new ThemedCvRenderer());
var cv = await variants.CreateAsync("owner", "CV", null, new CvVariantSettings { Headline = "Old headline" }, default);
await variants.SaveAsync("owner", cv.Id, null, new CvVariantSettings { Headline = "Saved headline" }, "manual", 1, default);
current.SetupGet(x => x.UserId).Returns(caller);
await using var db = new JobTrackerContext(options, current.Object);
var renderer = new Mock<IThemedCvRenderer>();
renderer.Setup(x => x.Render(It.IsAny<CvRenderModel>(), It.IsAny<CvTheme>(), It.IsAny<CvVariantSettings>()))
.Returns((CvRenderModel model, CvTheme theme, CvVariantSettings settings) => new ThemedCvRenderer().Render(model, theme, settings));
var service = new CvVariantService(db, new CareerProfileService(db), renderer.Object);
var pdf = new Mock<ICvPdfExporter>();
pdf.Setup(x => x.ExportAsync(caller, It.IsAny<TailoredCvRenderResult>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new CvPdfArtifact("CV.pdf", "unused", [1, 2, 3]));
var user = new ApplicationUser { Id = caller };
var users = TestHostFactory.CreateUserManager(user);
users.Setup(x => x.GetUserAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(user);
var controller = new CvVariantController(users.Object, service, pdf.Object, Mock.Of<ISummarizerService>())
{ ControllerContext = new() { HttpContext = new DefaultHttpContext() } };
var result = await controller.ExportPdf(cv.Id, default, expectedVersion);
if (status == 200)
{
Assert.Equal(new byte[] { 1, 2, 3 }, Assert.IsType<FileContentResult>(result).FileContents);
pdf.Verify(x => x.ExportAsync(caller, It.Is<TailoredCvRenderResult>(r => r.Html.Contains("Saved headline") && !r.Html.Contains("Old headline")), It.IsAny<CancellationToken>()), Times.Once);
}
else
{
if (status == 409)
{
var conflict = Assert.IsType<ObjectResult>(result);
Assert.Equal(409, conflict.StatusCode);
Assert.Equal("cv_revision_conflict", JsonSerializer.SerializeToElement(conflict.Value).GetProperty("code").GetString());
}
else Assert.IsType<NotFoundResult>(result);
pdf.VerifyNoOtherCalls();
renderer.VerifyNoOtherCalls();
}
}
}