Files
jobtrackingapp/JobTrackerApi.Tests/CompanyCreateCompatibilityTests.cs
T

113 lines
5.1 KiB
C#

using System.Security.Claims;
using JobTrackerApi.Controllers;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
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 CompanyCreateCompatibilityTests
{
[Fact]
public async Task Exact_Norwegian_name_reuses_owned_company_without_overwriting_existing_fields()
{
await using var fixture = await Fixture.CreateAsync();
var existing = new Company { OwnerUserId = "owner-a", Name = "Ærlig Økonomi Ås", Location = "Original location", Source = "Finn", RecruiterEmail = "retained@example.test" };
fixture.Db.Companies.Add(existing);
await fixture.Db.SaveChangesAsync();
var result = await fixture.Controller.Create(new(" Ærlig Økonomi Ås ", "Imported location", "LinkedIn"), default);
var company = Assert.IsType<Company>(Assert.IsType<OkObjectResult>(result.Result).Value);
Assert.Equal(existing.Id, company.Id);
Assert.Equal("owner-a", company.OwnerUserId);
Assert.Equal("Ærlig Økonomi Ås", company.Name);
Assert.Equal("Original location", company.Location);
Assert.Equal("Finn", company.Source);
Assert.Equal("retained@example.test", company.RecruiterEmail);
Assert.Equal(1, await fixture.Db.Companies.IgnoreQueryFilters().CountAsync());
}
[Fact]
public async Task Ascii_case_insensitive_reuse_and_trimmed_input_remain_compatible()
{
await using var fixture = await Fixture.CreateAsync();
var existing = new Company { OwnerUserId = "owner-a", Name = "Northwind AS", Location = "Original location", Source = "Finn" };
fixture.Db.Companies.Add(existing);
await fixture.Db.SaveChangesAsync();
var result = await fixture.Controller.Create(new(" nORTHWIND aS ", "Another location", "LinkedIn"), default);
var company = Assert.IsType<Company>(Assert.IsType<OkObjectResult>(result.Result).Value);
Assert.Equal(existing.Id, company.Id);
Assert.Equal("Northwind AS", company.Name);
Assert.Equal("Original location", company.Location);
Assert.Equal("Finn", company.Source);
Assert.Equal(1, await fixture.Db.Companies.CountAsync());
}
[Fact]
public async Task An_identical_foreign_name_creates_a_separate_owned_company_and_preserves_source_normalization()
{
await using var fixture = await Fixture.CreateAsync();
var foreign = new Company { OwnerUserId = "owner-b", Name = "Ærlig AS", Location = "Private location", Source = "Private source", RecruiterEmail = "private@example.test" };
fixture.Db.Companies.Add(foreign);
await fixture.Db.SaveChangesAsync();
var result = await fixture.Controller.Create(new(" Ærlig AS ", " Bergen ", "https://www.nav.no/jobs"), default);
var company = Assert.IsType<Company>(Assert.IsType<CreatedAtActionResult>(result.Result).Value);
Assert.NotEqual(foreign.Id, company.Id);
Assert.Equal("owner-a", company.OwnerUserId);
Assert.Equal("Ærlig AS", company.Name);
Assert.Equal("Bergen", company.Location);
Assert.Equal("NAV", company.Source);
Assert.Null(company.RecruiterEmail);
Assert.Equal(1, await fixture.Db.Companies.CountAsync());
Assert.Equal(2, await fixture.Db.Companies.IgnoreQueryFilters().CountAsync());
var retained = await fixture.Db.Companies.IgnoreQueryFilters().AsNoTracking().SingleAsync(value => value.Id == foreign.Id);
Assert.Equal("owner-b", retained.OwnerUserId);
Assert.Equal("Private location", retained.Location);
Assert.Equal("Private source", retained.Source);
Assert.Equal("private@example.test", retained.RecruiterEmail);
}
private sealed class Fixture(SqliteConnection connection, JobTrackerContext db) : IAsyncDisposable
{
public JobTrackerContext Db { get; } = db;
public CompaniesController Controller { get; } = new(db)
{
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = new ClaimsPrincipal(new ClaimsIdentity([new Claim(ClaimTypes.NameIdentifier, "owner-a")], "test")),
},
},
};
public static async Task<Fixture> CreateAsync()
{
var connection = new SqliteConnection("Data Source=:memory:");
await connection.OpenAsync();
var currentUser = new Mock<ICurrentUserService>();
currentUser.SetupGet(value => value.UserId).Returns("owner-a");
var db = new JobTrackerContext(new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(connection).Options, currentUser.Object);
await db.Database.EnsureCreatedAsync();
return new Fixture(connection, db);
}
public async ValueTask DisposeAsync()
{
await Db.DisposeAsync();
await connection.DisposeAsync();
}
}
}