Files
atomic-design-poc/backend/tests/BigRegister.Tests/StamdataValidationTests.cs
T
ehoandClaude Opus 4.8 0e77faf351 feat(stamdata): admin stamdata maintenance editor (beheer)
Realizes ADR-0004's "future low-code editor that commits a PR": an
admin-only stamdata maintenance editor built on the stamdata-as-code
foundation.

Backend: `professions` moves from a hardcoded C# dictionary to an embedded
`professions.json` data-file (typed as `ProfessionMapping`) with valid-time
(geldigVan/geldigTot, half-open). A generic, reflection-driven
StamdataCatalog/StamdataTable/StamdataFile describes every table so one
endpoint pair + one grid editor serve all of them; add a table in one line.
Two read-only, admin-gated endpoints (GET /stamdata, GET /stamdata/{table}
?peildatum=) — no runtime write path. Generic build gate
`Every_catalog_table_is_valid` (keys non-blank, no overlapping validity,
well-formed windows).

Frontend: new `beheer` context (route beheer/stamdata, capabilityGuard
'stamdata:edit'). A schema-driven grid editor edits rows locally; download()
emits {table}.json for the admin to commit as a reviewed PR (no mutation
command — the CI build + StamdataValidationTests stay the authority).

Full gate GREEN both sides; gen:api leaves no drift; new stamdata story
passes axe. See WP-29 + ADR-0004.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 13:43:51 +02:00

71 lines
2.6 KiB
C#

using BigRegister.Api.Data;
using BigRegister.Domain.Diplomas;
using BigRegister.Stamdata;
namespace BigRegister.Tests;
/// <summary>
/// The compile-time gate for business-editable stamdata (ADR-0004). The C# compiler
/// already catches shape/type mistakes; these tests catch the referential integrity it
/// can't, so a bad config edit fails the build instead of reaching production.
/// </summary>
public class StamdataValidationTests
{
[Fact]
public void Every_seeded_diploma_program_maps_to_a_known_profession()
{
// The dangling-reference guard: a seed program with no entry in Professions would
// silently render "Onbekend" to the user. Fail the build instead.
foreach (var d in SeedData.Diplomas)
Assert.True(DiplomaRules.ProfessionFor(d) != "Onbekend",
$"Diploma program '{d.Opleiding}' has no profession in Stamdata.Professions.");
}
[Fact]
public void Profession_map_has_no_blank_programs_or_professions()
{
Assert.All(Professions.ByProgram, kv =>
{
Assert.False(string.IsNullOrWhiteSpace(kv.Key), "A profession-map program key is blank.");
Assert.False(string.IsNullOrWhiteSpace(kv.Value), $"Program '{kv.Key}' maps to a blank profession.");
});
}
[Fact]
public void Manual_professions_are_non_empty_and_distinct()
{
var professions = DiplomaRules.ManualProfessions();
Assert.NotEmpty(professions);
Assert.Equal(professions.Count, professions.Distinct().Count());
}
[Fact]
public void Every_policy_question_has_an_id_and_wording()
{
Assert.All(PolicyQuestions.All, q =>
{
Assert.False(string.IsNullOrWhiteSpace(q.Id), "A policy question has a blank id.");
Assert.False(string.IsNullOrWhiteSpace(q.Vraag), $"Policy question '{q.Id}' has blank wording.");
});
}
[Fact]
public void Manual_question_set_has_distinct_ids() // no field is asked twice
{
var ids = PolicyQuestions.ManualSet.Select(q => q.Id).ToList();
Assert.Equal(ids.Count, ids.Distinct().Count());
}
// The GENERIC gate (ADR-0004): every table registered in the catalog is validated the
// same way — its JSON deserializes into its typed record, keys are non-blank and don't
// overlap in time, and valid-time windows are well-formed. A new stamdata type is covered
// the moment it's added to StamdataCatalog; no new test needed. A bad edit fails the build.
[Fact]
public void Every_catalog_table_is_valid()
{
foreach (var table in StamdataCatalog.All)
Assert.True(table.Validate().Count == 0,
$"Stamdata table '{table.Id}' has problems: {string.Join("; ", table.Validate())}");
}
}