fix(companies): reuse exact Norwegian company names
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user