| """Tests for InvoiceGuard data models.""" | |
| import sys | |
| import os | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) | |
| from models import ( | |
| ActionType, | |
| DecisionType, | |
| ExceptionType, | |
| TaskID, | |
| Difficulty, | |
| InvoiceGuardAction, | |
| InvoiceGuardObservation, | |
| InvoiceGuardState, | |
| GraderResult, | |
| Invoice, | |
| InvoiceLineItem, | |
| PurchaseOrder, | |
| POLineItem, | |
| GoodsReceiptNote, | |
| GRNLineItem, | |
| VendorProfile, | |
| CompanyPolicy, | |
| CaseData, | |
| CaseHistory, | |
| GroundTruth, | |
| ) | |
| class TestEnums: | |
| def test_action_types_count(self): | |
| assert len(ActionType) == 12 | |
| def test_decision_types(self): | |
| expected = { | |
| "approve_for_payment", | |
| "place_on_hold", | |
| "reject_invoice", | |
| "escalate_for_supervisor_review", | |
| } | |
| assert {d.value for d in DecisionType} == expected | |
| def test_exception_types_include_key_variants(self): | |
| values = {e.value for e in ExceptionType} | |
| assert "clean_match" in values | |
| assert "duplicate_invoice" in values | |
| assert "price_mismatch" in values | |
| assert "partial_receipt" in values | |
| assert "mixed_discrepancy" in values | |
| def test_task_ids_minimum_12_canonical(self): | |
| canonical = [t for t in TaskID if not any(c in t.value for c in ["b_", "c_"])] | |
| assert len(canonical) >= 12 | |
| def test_difficulty_levels(self): | |
| assert set(d.value for d in Difficulty) == {"easy", "moderate", "hard"} | |
| class TestAction: | |
| def test_minimal_action(self): | |
| a = InvoiceGuardAction(action_type=ActionType.inspect_purchase_order) | |
| assert a.action_type == ActionType.inspect_purchase_order | |
| assert a.final_decision is None | |
| assert a.evidence_references == [] | |
| def test_resolution_action(self): | |
| a = InvoiceGuardAction( | |
| action_type=ActionType.submit_final_resolution, | |
| final_decision=DecisionType.approve_for_payment, | |
| exception_type=ExceptionType.clean_match, | |
| evidence_references=["inspect_purchase_order", "compare_quantity"], | |
| explanation="All documents match.", | |
| ) | |
| assert a.final_decision == DecisionType.approve_for_payment | |
| assert len(a.evidence_references) == 2 | |
| class TestObservation: | |
| def test_defaults(self): | |
| obs = InvoiceGuardObservation() | |
| assert obs.case_id == "" | |
| assert obs.available_actions == [] | |
| assert obs.suggested_next_actions == [] | |
| assert obs.remaining_steps == 0 | |
| assert obs.done is False | |
| assert obs.grader_result == {} | |
| def test_populated(self): | |
| obs = InvoiceGuardObservation( | |
| case_id="CASE-001", | |
| task_id="task_1_clean_match", | |
| difficulty="easy", | |
| remaining_steps=10, | |
| suggested_next_actions=["inspect_purchase_order"], | |
| ) | |
| assert obs.case_id == "CASE-001" | |
| assert obs.suggested_next_actions == ["inspect_purchase_order"] | |
| class TestState: | |
| def test_defaults(self): | |
| s = InvoiceGuardState() | |
| assert s.step_count == 0 | |
| assert s.actions_taken == [] | |
| assert s.is_finalized is False | |
| assert s.cumulative_reward == 0.0 | |
| def test_mutation(self): | |
| s = InvoiceGuardState() | |
| s.actions_taken.append("inspect_purchase_order") | |
| s.step_count = 1 | |
| assert len(s.actions_taken) == 1 | |
| class TestGraderResult: | |
| def test_valid_score(self): | |
| r = GraderResult(score=0.85) | |
| assert r.score == 0.85 | |
| assert r.explanation_score == 0.0 | |
| def test_score_bounds(self): | |
| r = GraderResult(score=0.0) | |
| assert r.score == 0.0 | |
| r = GraderResult(score=1.0) | |
| assert r.score == 1.0 | |
| class TestBusinessEntities: | |
| def test_invoice_creation(self): | |
| inv = Invoice( | |
| invoice_number="INV-001", | |
| supplier_name="Test Corp", | |
| supplier_id="SUP-001", | |
| invoice_date="2024-01-01", | |
| po_reference="PO-001", | |
| line_items=[ | |
| InvoiceLineItem( | |
| item_code="ITM-A", | |
| description="Widget", | |
| quantity_billed=10, | |
| unit_price_billed=5.0, | |
| line_total_billed=50.0, | |
| ) | |
| ], | |
| subtotal=50.0, | |
| tax=5.0, | |
| total_amount=55.0, | |
| ) | |
| assert inv.currency == "USD" | |
| assert len(inv.line_items) == 1 | |
| def test_company_policy_defaults(self): | |
| p = CompanyPolicy() | |
| assert p.quantity_tolerance_pct == 5.0 | |
| assert p.price_tolerance_pct == 5.0 | |
| assert p.duplicate_check_enabled is True | |