Skip to content

test(parsing): #204 ClassMap regression tests — Rule/ArgumentVirtue/Scenario/Virtue (+9, 159→168) - #476

Merged
jsboige merged 1 commit into
masterfrom
test/204-classmap-regression
Jun 15, 2026
Merged

test(parsing): #204 ClassMap regression tests — Rule/ArgumentVirtue/Scenario/Virtue (+9, 159→168)#476
jsboige merged 1 commit into
masterfrom
test/204-classmap-regression

Conversation

@jsboige

@jsboige jsboige commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

9 additive ClassMap regression tests for the 4 entity types that carried historical mapping bugs (Fallacy already covered). Baseline 159/0/5 → 168/0/5 (proven by full suite run).

Why

CsvParserTests.cs only exercises a dummy FallacyRecord/CsvParser on tiny fixtures — it never touches the real entity ClassMaps. So the regressions documented in CLAUDE.md (Rule.GetId() empty, ArgumentVirtue.Pk unmapped, accented FR headers, #216-adjacent mapping) had zero regression coverage. Issue #204 flagged "CsvHelper mapping — verify all entity ClassMap classes parse correctly with real CSV headers" as Medium Priority.

Design — real load path, self-contained

Tests call CsvBase<T,TMap>.LoadFromContent(inlineCsv) — the actual production loader — which:

  • registers the entity ClassMap,
  • applies PrepareHeaderForMatch (strips diacritics/underscore/hyphen/space + lowercases) so accented FR headers resolve,
  • treats MissingFieldFound as a non-fatal log,
  • assigns 0-based RowIndex post-load (used by Rule.GetId()).

Inline CSV = self-contained, no external fixture files. No existing test or production code modified (additive only).

Coverage

Entity Tests Headline regression guarded
Rule (4) full column mapping · GetId()==Pk · GetId()==Rules_01/02/03 from RowIndex when Pk absent · optional es/ar/fa/zh absent → no throw the Rule.GetId() empty bug (now Rules_01…)
ArgumentVirtue (2) pkPk + GetId()==Pk · optional en/ru/pt/es absent → no throw the ArgumentVirtue.Pk unmapped bug
Scenario (2) accented FR headers (coordonnées/catégorie/sous-catégorie/édition février 2022) resolve · GetId()==path PrepareHeaderForMatch diacritics stripping (silent FR field zero-out if regressed)
Virtue (1) pk maps to both Id + Pk (VirtueClassMap maps both) so base GetId() resolves dual pk→Id+Pk mapping

Nuance discovered (documented in test comments)

CsvHelper has two distinct hooks: MissingFieldFound (overridden in CsvBase → logs only) and HeaderValidated (not overridden → keeps default that throws ValidationException if a non-Optional ClassMap member is absent from the header). This is why the real CSVs carry complete headers, and why the test CSVs for Scenario/ArgumentVirtue/Virtue include every non-Optional column. Not a bug — the tests document the real contract.

DoD

  • ✅ 159 → 168 pass / 0 fail / 5 skip (full suite)
  • ✅ Additive only (1 new file, 247 lines)
  • ✅ Build green (0 errors)
  • ✅ Real code path (no mocking of the loader)

Scope / notes

Docs/test only — no CSV, no template, no rendering, no config. Serves #204 (test coverage expansion). Release-independent: the mapping logic doesn't change regardless of the visual validation outcome.

🤖 Worker po-2024 on dispatch 3a0d2l. Verdict QA visuelle stays ai-01 — this is unit-test parsing logic, not a visual PASS.

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

…/Scenario/Virtue

Adds 9 additive unit tests covering the real CsvHelper ClassMaps of the four
entity types that carried historical mapping bugs (Fallacy already has coverage).
Baseline 159/0/5 -> 168/0/5.

Tests exercise the REAL load path (CsvBase<T,TMap>.LoadFromContent) — which
registers the ClassMap, applies PrepareHeaderForMatch (diacritics/underscore/
hyphen/space stripping + lowercasing), treats MissingFieldFound as a non-fatal
log, and assigns 0-based RowIndex post-load — using self-contained inline CSV
(no external fixture files). No existing test or production code is modified.

Rule (4):
- every column -> property (pk, Text + 8 localized, print_and_play)
- GetId() returns Pk when present
- GetId() returns sequential Rules_01/02/03 from RowIndex when Pk absent (the
  historical bug: GetId() used to return string.Empty)
- optional localized columns (es/ar/fa/zh) absent -> no throw, props null

ArgumentVirtue (2):
- pk column -> Pk property + GetId()==Pk (historical bug: Id/pk was unmapped)
- optional en/ru/pt/es columns absent -> no throw

Scenario (2):
- accented FR headers (coordonnées, catégorie, sous-catégorie,
  édition février 2022) resolve via PrepareHeaderForMatch — a regression here
  would silently zero out the FR fields
- GetId() returns the path column

Virtue (1):
- pk column maps to BOTH Id (CsvBase base) and Pk (VirtueClassMap maps both),
  so base GetId() resolves

DoD: 159->168 pass, 0 fail, 5 skip. Additive only. Docs/issue #204.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jsboige
jsboige merged commit fc4c1d2 into master Jun 15, 2026
3 checks passed
@jsboige
jsboige deleted the test/204-classmap-regression branch June 15, 2026 05:08
jsboige added a commit that referenced this pull request Jun 15, 2026
…columns guard (+2) (#485)

Fallacy is the largest entity (~1408 rows) yet had no LoadFromContent regression
coverage — the #476 note "Fallacy already has coverage elsewhere" is stale (only an
incidental ClassMap registration in MmGeneratorTests existed, asserting no mappings).

Two tests via the real CsvBase<Fallacy,FallacyClassMap>.LoadFromContent path:
- MapsRequiredColumns: pins pk→PK+Id (GetId resolves), FR required columns, and that
  present localized columns (en/zh) map.
- OptionalLocalizedColumns_AbsentDoesNotThrow [highest value]: a FR-only header set
  parses without throwing and leaves every representative Optional column null across
  all 8 languages + Latin/print_and_play. Guards the multilingual harvest — a single
  localized column losing its .Optional() would crash HeaderValidated (#216/#477 class).

Additive only: new file, no existing test/production code modified.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jun 15, 2026
…HeaderValidationException (#488)

New additive test file pinning the bidirectional CSV load contract of the
production CsvBase<T,TMap>.LoadFromContent (CsvHelper 31.0.4). The existing
ClassMap regression suites (#476 EntityClassMapRegressionTests, #485
FallacyClassMapRegressionTests) covered only ONE direction of the contract
("Optional absent -> no throw"). This pins the inverse half + isolation.

Contract halves via a synthetic ContractEntity (decoupled from evolving
domain ClassMaps), exercising the REAL CsvBase configuration:
- required (non-Optional) column absent from header -> HeaderValidationException.
  The guard that catches a dropped .Optional() at load time instead of silently
  zeroing a field (the #216/#477 localization fragility class).
- Optional column absent from header -> no throw, property null.
- short data row -> MissingFieldFound (non-fatal Logger override) -> no throw;
  the missing bound field resolves to EMPTY STRING, not null (distinct from the
  Optional-absent-from-header case which yields null).

3 tests, all green. Full suite 251 passed / 0 failed / 5 skipped (no regression).
Additive only: no production code or existing test modified.

Dispatch 4rkh1s secondaire (#204 fragile zone, new test file).

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jun 20, 2026
…sts) (#561)

Add TestFallacyCardClassMapRegressionTests — the LAST entity ClassMap without a
dedicated regression suite. This closes the ClassMap matrix at 100%: Fallacy (#485),
Rule/ArgumentVirtue/Scenario (#476), Virtue (#559), DnnUiString, and now TestFallacyCard.

TestFallacyCard is the simplified fallacy entity for visual-test card generation. Its
ClassMap declares 5 columns ALL required (non-Optional): Id, Title, Type,
IllustrationPath, Description.

5 contract tests via the real load path CsvBase<T,TMap>.LoadFromContent:
- MapsAllColumns: all 5 required columns map to their properties.
- GetIdReturnsId: GetId() returns Id (the image-generator output-dictionary key).
- RequiredColumnAbsent_Throws: a required column drift fails LOUD
  (HeaderValidationException), not silent null — the data-loss-prevention contract.
- ShortRow_DoesNotThrow: a ragged row yields string.Empty for missing fields
  (MissingFieldFound is a log callback, not throw) — mirrors CsvBaseStrictContractTests.
- MultipleRows_LoadInOrder.

This is the ai-01 SECONDAIRE dispatch ("TestFallacyCard ClassMap — ferme la matrice").
Additive only, no production code change. Full suite green (434/0/5, baseline 429 + 5).

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant