Unit test AutoApprovalEvaluator for all threshold combinations
epic-mileage-reimbursement-entry-infrastructure-task-009 — Write exhaustive unit tests for AutoApprovalEvaluator covering all decision paths: below threshold without attachment, below threshold with attachment, at exact threshold, above threshold, zero distance, and null/missing org config defaults. Verify ClaimStatus output is deterministic for every combination.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Build minimal test-only factory helpers at the top of the test file to construct MileageClaim and OrgConfiguration with sensible defaults. This makes each test a one-liner asserting only the variable under test. Example: expect(evaluator.evaluate(buildClaim(distanceKm: 40), buildOrgConfig(threshold: 50)), ClaimStatus.auto_approved). Validate that the test names are readable as a specification document — a non-technical reviewer should understand each test case from its description alone.
Consider using a parameterised test approach with a list of (input, expected) tuples to cover all 8 paths with minimal duplication.
Testing Requirements
Pure unit tests using flutter_test. Use factory helper functions (buildClaim({distanceKm, attachments}), buildOrgConfig({threshold})) to reduce boilerplate. Group tests into: group('auto_approved paths', ...), group('pending_review paths', ...), group('boundary conditions', ...), group('null/missing config', ...). Each group should have clear test names that read as business rules.
No mocks needed. 100% branch coverage of evaluate() method required.
Supabase Row Level Security policies for mileage_claims may require complex join conditions to distinguish peer mentor (own claims only) from coordinator (chapter-scoped claims) access. If the RLS policy is misconfigured, coordinators could see claims outside their chapter scope or peer mentors could read other users' data, causing a data privacy incident.
Mitigation & Contingency
Mitigation: Write RLS policy SQL as part of this epic with explicit test cases for each role. Use Supabase's built-in policy testing tools and add integration tests that assert cross-user data isolation before merging.
Contingency: If RLS configuration proves too complex to test reliably within the epic, add an application-layer guard in the adapter that filters query results by authenticated user ID as a defence-in-depth measure while the policy is corrected.
Norwegian tax authority reimbursement rounding rules may change or may not be publicly documented in machine-readable form. Using the wrong rounding convention could cause systematic over- or under-payment, leading to compliance issues for the organisation.
Mitigation & Contingency
Mitigation: Source the exact rounding specification from HLF's finance team before implementing MileageCalculationService. Document the rule as a comment in the source code and link to the authoritative reference.
Contingency: If the rule is ambiguous, implement both truncation and half-up rounding behind a configuration flag so the organisation can switch without a code release.
SharedPreferences reads and writes are asynchronous. If the distance prefill service (built in the next epic) calls LocalDistanceCache concurrently with a post-submission write, a race condition could result in the cache returning a stale or partially written value, causing the next form load to show an incorrect default.
Mitigation & Contingency
Mitigation: Wrap all SharedPreferences access in LocalDistanceCache with sequential async operations and document the non-concurrent usage contract in the class API.
Contingency: If race conditions are observed in testing, introduce a simple mutex pattern using a Completer to serialise cache operations.