96816186cb
HumanLanguageCatalog built its lookup table solely from CultureInfo.GetCultures, so which languages counted as human languages depended on the host's ICU data rather than on the CV. Measured: 806 cultures on a normal Windows or Linux machine, exactly 1 under globalization-invariant mode, and an English-only subset on a container with trimmed ICU data. Consequences by environment, all silent: - full ICU: correct - trimmed ICU: canonical names present in the reduced data survive and the rest are dropped, so a CV keeps English and loses Norwegian - invariant: every language is dropped and a CV import loses its Languages section entirely, with no error The tests were right and are unchanged. Seed the catalog explicitly with the languages a CV realistically lists, before the culture enumeration, which still runs and still adds breadth. Nothing in the seed collides with a technical skill -- Go, Java, Swift, Rust and Basic are deliberately absent, and Basic is also a proficiency level. Verified 420 tests pass in four environments: Windows and Linux, each with full ICU and with DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1. Before this change the invariant runs failed 5 tests. No test was modified, skipped or relaxed. Added HumanLanguageCatalogTests to pin the seeded catalog, confirmed non-vacuous by removing the seed and watching 15 tests fail. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
2.0 KiB
C#
58 lines
2.0 KiB
C#
using JobTrackerApi.Models;
|
|
using Xunit;
|
|
|
|
namespace JobTrackerApi.Tests;
|
|
|
|
// The catalog used to be built solely from CultureInfo.GetCultures, so which languages it
|
|
// recognised depended on the host's ICU data: 806 cultures on a normal machine, exactly 1
|
|
// under globalization-invariant mode. CV imports silently lost their Languages section on a
|
|
// container with trimmed or absent ICU data, and every existing test still passed locally.
|
|
//
|
|
// These pin the explicitly seeded catalog, so deleting the seed list fails here rather than
|
|
// in production on a machine nobody tested.
|
|
public sealed class HumanLanguageCatalogTests
|
|
{
|
|
[Theory]
|
|
[InlineData("English")]
|
|
[InlineData("Norwegian")]
|
|
[InlineData("French")]
|
|
[InlineData("Spanish")]
|
|
[InlineData("German")]
|
|
[InlineData("Arabic")]
|
|
[InlineData("Chinese")]
|
|
[InlineData("Polish")]
|
|
public void Common_languages_resolve_without_relying_on_host_culture_data(string language)
|
|
{
|
|
Assert.Equal(language, HumanLanguageCatalog.NormalizeLanguageName(language));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("norsk")]
|
|
[InlineData("bokmål")]
|
|
[InlineData("nynorsk")]
|
|
public void Norwegian_aliases_resolve_to_the_canonical_name(string alias)
|
|
{
|
|
Assert.Equal("Norwegian", HumanLanguageCatalog.NormalizeLanguageName(alias));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("C#")]
|
|
[InlineData("Leadership")]
|
|
[InlineData("Public speaking")]
|
|
[InlineData("Go")] // a programming language, not a human one
|
|
[InlineData("Java")] // Javanese is a language; Java is not
|
|
[InlineData("Swift")]
|
|
[InlineData("Rust")]
|
|
public void Technical_skills_are_not_treated_as_human_languages(string skill)
|
|
{
|
|
Assert.Null(HumanLanguageCatalog.NormalizeLanguageName(skill));
|
|
}
|
|
|
|
[Fact]
|
|
public void A_language_embedded_in_a_phrase_is_extracted_with_its_level()
|
|
{
|
|
Assert.Equal("Norwegian", HumanLanguageCatalog.NormalizeLanguageName("Native Norwegian speaker"));
|
|
Assert.Equal("Native", HumanLanguageCatalog.ExtractLevel("Native Norwegian speaker"));
|
|
}
|
|
}
|