from pathlib import Path import tempfile import unittest from docx import Document from pypdf import PdfReader from generate import fragments, generate_case, load_corpus from evaluate import evaluate_case, evaluate_run class GeneratorTests(unittest.TestCase): def test_corpus_is_unique_split_and_independently_annotated(self): corpus = load_corpus(Path(__file__).with_name("corpus.json")) self.assertGreaterEqual(len(corpus), 16) self.assertEqual({c["split"] for c in corpus}, {"development", "frozen"}) ambiguous = [c for c in corpus if c.get("abstentionRequired")] self.assertTrue(ambiguous) self.assertTrue(all(c["unresolved"] for c in ambiguous)) def test_provenance_expectations_name_existing_literal_source_occurrences(self): for case in load_corpus(Path(__file__).with_name("corpus.json")): for path, reference in case.get("provenance", {}).items(): matches = [text for text in fragments(case) if reference["text"] in text] self.assertGreaterEqual(len(matches), reference.get("occurrence", 1), (case["id"], path)) value = {**case["expected"], "otherSections": case.get("unresolved", [])} for part in path.split("."): value = value[int(part)] if isinstance(value, list) else value[part] if isinstance(value, str): self.assertIn(value, reference["text"], (case["id"], path)) def test_generator_creates_real_lists_multirow_table_unicode_and_page_break(self): case = {"id": "structure", "blocks": [{"type": "heading", "text": "Utdanning"}, {"type": "list", "text": "Åse Øvrebø"}, {"type": "table", "headers": ["Institution", "Qualification"], "rows": [["A", "BSc"], ["B", "MSc"]]}, {"type": "page_break"}, {"text": "Tromsø"}]} with tempfile.TemporaryDirectory() as directory: paths = generate_case(case, Path(directory)) word = Document(paths["docx"]) self.assertEqual(word.paragraphs[0].style.name, "Heading 2") self.assertEqual(word.paragraphs[1].style.name, "List Bullet") self.assertEqual(len(word.tables[0].rows), 3) self.assertEqual([c.text for c in word.tables[0].rows[0].cells], ["Institution", "Qualification"]) pdf = PdfReader(paths["pdf"]) self.assertEqual(len(pdf.pages), 2) self.assertIn("Åse Øvrebø", pdf.pages[0].extract_text()) self.assertIn("Tromsø", pdf.pages[1].extract_text()) with self.assertRaises(FileExistsError): generate_case(case, Path(directory)) class OracleTests(unittest.TestCase): def test_correct_abstention_is_scored_separately_from_typed_recall(self): case = {"expected": {}, "blocks": [{"text": "A"}, {"text": "Engineer"}], "unresolved": [{"title": None, "items": ["A", "Engineer"]}], "abstentionRequired": True} result = evaluate_case(case, {"profile": {"otherSections": [{"items": ["A", "Engineer"]}]}}, {"ok": True, "text": "A\nEngineer", "blocks": []}) self.assertTrue(result["abstention"]["correct"]) self.assertEqual(result["factual"]["falsePositive"], 0) self.assertEqual(result["unresolved"]["recall"], 1) fabricated = evaluate_case(case, {"profile": {"jobs": [{"company": "A", "title": "Engineer"}]}}, {}) self.assertFalse(fabricated["abstention"]["correct"]) self.assertEqual(fabricated["factual"]["falsePositive"], 2) def test_second_occurrence_provenance_cannot_point_to_first_matching_block(self): case = {"expected": {"jobs": [{"company": "A", "title": "Engineer"}]}, "blocks": [], "provenance": {"jobs.0.company": {"text": "Company: A", "occurrence": 2}}} profile = {"jobs": case["expected"]["jobs"], "metadata": {"fields": { "jobs.0.company": {"sourceBlockId": "b1", "sourcePage": 1}}}} extraction = {"blocks": [{"id": "b1", "text": "Company: A", "page": 1}, {"id": "b2", "text": "Company: A", "page": 2}]} result = evaluate_case(case, {"profile": profile}, extraction) self.assertEqual(result["factual"]["recall"], 1) self.assertEqual(result["provenance"]["correct"], 0) profile["metadata"]["fields"]["jobs.0.company"] = {"sourceBlockId": "b2", "sourcePage": 2} self.assertEqual(evaluate_case(case, {"profile": profile}, extraction)["provenance"]["correct"], 1) def test_swapped_associations_fail_records_and_dates_without_hiding_extra_fields(self): truth = {"jobs": [{"company": "A", "title": "Engineer", "start": "2020", "end": "2021", "bullets": ["First"]}, {"company": "A", "title": "Engineer", "start": "2022", "end": "2023", "bullets": ["Second"]}]} actual = [{**truth["jobs"][0], "bullets": ["Second"]}, {**truth["jobs"][1], "bullets": ["First"]}] result = evaluate_case({"expected": truth, "blocks": []}, {"profile": {"jobs": actual}}, {}) self.assertEqual(result["records"]["jobs"]["complete"], 0) self.assertEqual(result["factual"]["falsePositive"], 2) self.assertLess(result["perField"]["jobs.bullets"]["f1"], 1) def test_missing_output_counts_against_completion_and_recovery(self): corpus = [{"id": "a", "split": "frozen", "expected": {"skills": ["C#"]}, "blocks": [{"text": "C#"}]}] result = evaluate_run(corpus, {}, {}) self.assertEqual(result["completion"], 0) self.assertEqual(result["interpretation"]["recall"], 0) self.assertEqual(result["doclingRecovery"]["literalFragmentRecall"], 0) self.assertEqual(result["reviewedMapping"], "NOT RUN") self.assertEqual(result["realAiAccuracy"], "BLOCKED") def test_unknown_source_and_list_markers_have_independent_preservation_score(self): case = {"expected": {}, "blocks": [], "unresolved": [{"title": "Work Experience", "items": ["Orphan detail"]}]} result = evaluate_case(case, {"profile": {"otherSections": [{"title": "Work Experience", "items": ["- Orphan detail", "Unexpected"]}]}}, {}) self.assertEqual(result["unresolved"]["truePositive"], 1) self.assertEqual(result["unresolved"]["falsePositive"], 1) self.assertEqual(result["unresolved"]["recall"], 1) def test_an_empty_typed_record_is_not_correct_abstention(self): case = {"expected": {}, "blocks": [], "unresolved": [{"items": ["Unknown"]}], "abstentionRequired": True} actual = {"jobs": [{}], "otherSections": [{"items": ["Unknown"]}]} self.assertFalse(evaluate_case(case, {"profile": actual}, {})["abstention"]["correct"]) if __name__ == "__main__": unittest.main()