Files
jobtrackingapp/JobTrackerApi.Tests/AttachmentFlagsRecomputeTests.cs
T

116 lines
4.6 KiB
C#

using JobTrackerApi.Controllers;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using JobTrackerApi.Tests.TestSupport;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Moq;
using Xunit;
namespace JobTrackerApi.Tests;
// JobApplication.HasResume/HasCoverLetter/HasPortfolio/HasOtherAttachment are derived from
// Attachment rows (backlog Wave 3), not manually settable. These tests exercise the single
// place they're written: AttachmentsController's Purpose-change and Delete paths.
public sealed class AttachmentFlagsRecomputeTests
{
[Fact]
public async Task Changing_purpose_to_resume_sets_HasResume()
{
await using var db = TestHostFactory.CreateInMemoryDb();
var (job, attachment) = await SeedJobWithAttachmentAsync(db, purpose: "other");
var controller = CreateController(db, Path.GetDirectoryName(attachment.FilePath));
var result = await controller.Rename(attachment.Id, new AttachmentsController.UpdateAttachmentRequest(null, "resume", null), CancellationToken.None);
Assert.IsType<NoContentResult>(result);
var updated = await db.JobApplications.SingleAsync(j => j.Id == job.Id);
Assert.True(updated.HasResume);
Assert.True(updated.HasOtherAttachment == false);
}
[Fact]
public async Task Deleting_the_only_resume_attachment_clears_HasResume()
{
await using var db = TestHostFactory.CreateInMemoryDb();
var (job, attachment) = await SeedJobWithAttachmentAsync(db, purpose: "resume");
var controller = CreateController(db, Path.GetDirectoryName(attachment.FilePath));
var result = await controller.Delete(attachment.Id, CancellationToken.None);
Assert.IsType<NoContentResult>(result);
var updated = await db.JobApplications.SingleAsync(j => j.Id == job.Id);
Assert.False(updated.HasResume);
}
[Fact]
public async Task Attachment_with_case_study_purpose_counts_as_other()
{
await using var db = TestHostFactory.CreateInMemoryDb();
var (job, attachment) = await SeedJobWithAttachmentAsync(db, purpose: "resume");
var controller = CreateController(db, Path.GetDirectoryName(attachment.FilePath));
await controller.Rename(attachment.Id, new AttachmentsController.UpdateAttachmentRequest(null, "case-study", null), CancellationToken.None);
var updated = await db.JobApplications.SingleAsync(j => j.Id == job.Id);
Assert.False(updated.HasResume);
Assert.True(updated.HasOtherAttachment);
}
private static async Task<(JobApplication Job, Attachment Attachment)> SeedJobWithAttachmentAsync(JobTrackerContext db, string purpose)
{
var company = new Company { Name = "Acme", OwnerUserId = "user-1" };
db.Companies.Add(company);
await db.SaveChangesAsync();
var job = new JobApplication { JobTitle = "Backend Developer", CompanyId = company.Id, OwnerUserId = "user-1" };
db.JobApplications.Add(job);
await db.SaveChangesAsync();
var attachment = new Attachment
{
JobApplicationId = job.Id,
FileName = "file.pdf",
FilePath = Path.Combine(Path.GetTempPath(), $"jobtracker-attachment-test-{Guid.NewGuid():N}.pdf"),
FileType = "application/pdf",
FileSize = 100,
Purpose = purpose,
};
db.Attachments.Add(attachment);
await db.SaveChangesAsync();
job.HasResume = purpose == "resume";
job.HasOtherAttachment = purpose is not ("resume" or "cover-letter" or "portfolio");
await db.SaveChangesAsync();
return (job, attachment);
}
private static AttachmentsController CreateController(JobTrackerContext db, string? attachmentsRoot)
{
var tempRoot = Path.Combine(Path.GetTempPath(), $"jobtracker-attachments-tests-{Guid.NewGuid():N}");
Directory.CreateDirectory(tempRoot);
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Data:Root"] = tempRoot,
["Data:AttachmentsRoot"] = attachmentsRoot,
})
.Build();
var env = new Mock<IHostEnvironment>();
env.SetupGet(x => x.ContentRootPath).Returns(tempRoot);
var paths = new AppPaths(config, env.Object);
return new AttachmentsController(paths, db)
{
ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext() }
};
}
}