"""Tests for the case_type-driven verification test-case generation feature. Covers: registry determinism, correct rendering/ground-truth for every one of the 12 case types, companion-box behavior, and backward compatibility with the existing (non-case-type) generation path. """ from __future__ import annotations from src.config.loader import load_config from src.generator import GeneratorContext from src.verification.case_types import CASE_TABLE from src.verification.registry import SignerIdentityRegistry def _make_context(tmp_path, case_type: "str | None" = None, seed: int = 4242): overrides = [f"seed={seed}", f"paths.output_dir={tmp_path.as_posix()}", "generation.count=1"] if case_type is not None: overrides.append(f"quality.case_type={case_type}") config = load_config(overrides=overrides) return GeneratorContext(config) # --------------------------------------------------------------------- # # Registry # --------------------------------------------------------------------- # def test_registry_authorized_signer_is_deterministic(tmp_path): ctx1 = _make_context(tmp_path) ctx2 = _make_context(tmp_path) for template_id, template in ctx1.template_loader.discover().items(): for box in template.annotation.pages[0].signature_boxes: a = ctx1.identity_registry.authorized_signer_group(template_id, box.id) b = ctx2.identity_registry.authorized_signer_group(template_id, box.id) assert a == b def test_registry_display_name_is_stable_across_instances(tmp_path): ctx1 = _make_context(tmp_path) ctx2 = _make_context(tmp_path) group = ctx1.identity_registry._signer_groups[0] assert ctx1.identity_registry.display_name(group) == ctx2.identity_registry.display_name(group) def test_registry_foreign_authorized_picks_a_different_template(tmp_path): ctx = _make_context(tmp_path) group, foreign_template_id, foreign_box_id = ctx.identity_registry.foreign_authorized("bank_doc_01") assert foreign_template_id != "bank_doc_01" assert group == ctx.identity_registry.authorized_signer_group(foreign_template_id, foreign_box_id) # --------------------------------------------------------------------- # # Per-case-type ground truth # --------------------------------------------------------------------- # def test_all_case_types_produce_matching_verdict_and_reject_code(tmp_path): for code, spec in CASE_TABLE.items(): ctx = _make_context(tmp_path, case_type=code, seed=99) metadata, _, report = ctx.run_sample(1) v = metadata["verification"] assert v["case_type"] == code assert v["verdict"] == spec.verdict, f"{code}: verdict mismatch" assert v["reject_code"] == spec.reject_code, f"{code}: reject_code mismatch" assert report is not None and report.passed, ( f"{code}: validation failed: {[i.message for i in report.errors]}" ) def test_pass_cases_use_the_authorized_signer(tmp_path): for code in ("1a", "1b", "1d"): ctx = _make_context(tmp_path, case_type=code, seed=17) metadata, _, _ = ctx.run_sample(1) v = metadata["verification"] assert v["actual_signer_group"] == v["expected_signer_group"] assert v["actual_source_type"] == "genuine" assert v["companion"] is None def test_multi_signer_pass_case_fills_companion_correctly(tmp_path): ctx = _make_context(tmp_path, case_type="1c", seed=17) metadata, _, _ = ctx.run_sample(1) v = metadata["verification"] assert v["actual_signer_group"] == v["expected_signer_group"] assert v["companion"] is not None assert v["companion"]["filled"] is True assert v["companion"]["matches_expected"] is True def test_blank_cases_have_no_actual_signer(tmp_path): for code in ("2a", "5a"): ctx = _make_context(tmp_path, case_type=code, seed=5) metadata, _, _ = ctx.run_sample(1) v = metadata["verification"] assert v["actual_signer_group"] is None assert v["actual_source_type"] == "none" assert metadata["signature_source"]["signature_id"] is None ctx_5a = _make_context(tmp_path, case_type="5a", seed=5) metadata_5a, _, _ = ctx_5a.run_sample(1) assert metadata_5a["verification"]["companion"]["filled"] is True ctx_2a = _make_context(tmp_path, case_type="2a", seed=5) metadata_2a, _, _ = ctx_2a.run_sample(1) assert metadata_2a["verification"]["companion"] is None def test_identity_mismatch_cases_use_a_different_signer(tmp_path): for code in ("3a", "5b"): ctx = _make_context(tmp_path, case_type=code, seed=23) metadata, _, _ = ctx.run_sample(1) v = metadata["verification"] assert v["actual_signer_group"] != v["expected_signer_group"] assert v["actual_source_type"] == "genuine" def test_skilled_forgery_case_uses_forged_sample_of_the_authorized_signer(tmp_path): ctx = _make_context(tmp_path, case_type="3b", seed=23) metadata, _, _ = ctx.run_sample(1) v = metadata["verification"] assert v["actual_signer_group"] == v["expected_signer_group"] assert v["actual_source_type"] == "forged" def test_role_mismatch_cases_use_a_legitimately_registered_signer(tmp_path): ctx = _make_context(tmp_path, case_type="4a", seed=31) metadata, _, _ = ctx.run_sample(1) v = metadata["verification"] # The target box got the *companion* box's own authorized signer. assert v["actual_signer_group"] == v["companion"]["signer_group"] assert v["actual_signer_group"] != v["expected_signer_group"] ctx_4b = _make_context(tmp_path, case_type="4b", seed=31) metadata_4b, _, _ = ctx_4b.run_sample(1) v4b = metadata_4b["verification"] assert v4b["actual_signer_group"] != v4b["expected_signer_group"] def test_printed_text_case_has_no_biometric_identity(tmp_path): ctx = _make_context(tmp_path, case_type="2b", seed=11) metadata, _, _ = ctx.run_sample(1) v = metadata["verification"] assert v["actual_signer_group"] is None assert v["actual_source_type"] == "printed" # --------------------------------------------------------------------- # # Backward compatibility # --------------------------------------------------------------------- # def test_unset_case_type_is_unaffected(tmp_path): ctx = _make_context(tmp_path, case_type=None, seed=1) metadata, _, report = ctx.run_sample(1) v = metadata["verification"] assert v == { "case_type": None, "verdict": None, "reject_code": None, "target_box_id": None, "expected_signer_group": None, "expected_signer_script": None, "actual_signer_group": None, "actual_source_type": None, "actual_signer_script": None, "companion": None, } assert report is not None and report.passed # --------------------------------------------------------------------- # # Multi-script signer pool (Hindi/Bengali/Latin named identities) # --------------------------------------------------------------------- # def test_display_name_passes_through_real_names_but_generates_for_anonymous_groups(tmp_path): ctx = _make_context(tmp_path) assert ctx.identity_registry.display_name("Priya Sharma") == "Priya Sharma" generated = ctx.identity_registry.display_name("signer_0014") assert generated != "signer_0014" assert " " in generated # looks like "First Last" def test_named_signers_are_part_of_the_authorized_pool(tmp_path): ctx = _make_context(tmp_path) groups = set(ctx.signature_dataset.signer_groups()) assert {"Priya Sharma", "Raj Malhotra", "Vikram Singh", "Suman Das", "Anika Roy", "Carol Wong", "Henry Ooi"} <= groups def test_named_signer_flows_through_to_metadata_with_correct_script(tmp_path): """Find a sample that lands on a named, scripted signer and check it renders cleanly.""" ctx = _make_context(tmp_path, case_type="1a", seed=1) for i in range(1, 200): metadata, _, report = ctx.run_sample(i) v = metadata["verification"] if v["expected_signer_script"] != "latin": assert metadata["signer"]["name"] == v["expected_signer_group"] assert v["actual_signer_script"] == v["expected_signer_script"] assert report is not None and report.passed return raise AssertionError("No sample in range landed on a non-latin-script signer; widen the search range.") def test_forged_mode_degrades_gracefully_for_signers_without_forgeries(tmp_path): """Named signers have no CEDAR-style forged counterpart; sampling 'forged' for them should fall back to their genuine records rather than crash (SignatureDataset already logs a warning for this -- this just confirms the caller-facing behavior).""" ctx = _make_context(tmp_path) records = ctx.signature_dataset.records_for_group("Priya Sharma", source_filter="forged") assert len(records) > 0 assert all(r.signer_group == "Priya Sharma" for r in records) def test_unrecognized_case_type_label_falls_back_to_generic_path(tmp_path): """A free-text case_type not in CASE_TABLE behaves exactly like today's plain-label usage.""" ctx = _make_context(tmp_path, case_type="my-custom-label", seed=1) metadata, _, report = ctx.run_sample(1) assert metadata["verification"]["case_type"] is None assert metadata["quality"]["case_type"] == "my-custom-label" assert report is not None and report.passed