Unit test TerminologyCacheAdapter backends
epic-dynamic-terminology-and-labels-foundation-task-009 — Write flutter_test unit tests for TerminologyCacheAdapter using mocked SharedPreferences and Hive. Cover: write then read returns same map; read on empty cache returns null; clear removes persisted data; JSON serialization round-trips correctly for maps with special characters; multiple org IDs are isolated and do not overwrite each other; timestamp is stored alongside data for TTL checks.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
The contract test pattern (shared test function called for each backend) is the recommended approach — it avoids duplicating 8+ test cases for each backend and ensures consistent behavior. If TerminologyCacheAdapter wraps both SharedPreferences and Hive behind a single interface, define an abstract `CacheBackend` interface and test each concrete implementation independently. For JSON serialization, use `jsonEncode` / `jsonDecode` from `dart:convert`; do not use `toString()` on the map. Timestamp storage: serialize as `DateTime.toUtc().toIso8601String()` and deserialize with `DateTime.parse(...).toLocal()` — document the UTC convention in a code comment.
Ensure `setUp()` in each test group resets both the mock storage AND any in-memory state the adapter may hold.
Testing Requirements
Use `SharedPreferences.setMockInitialValues({})` in setUp() to reset state between tests. For Hive, use a fake in-memory box (implement a mock Box
Special character test: create a map with key `'norsk.æøå'` and value `'Norsk tekst: «hei» ny linje'` and assert round-trip fidelity. Timestamp test: capture DateTime.now() before write(), read back cachedAt, assert it is within 1 second of the captured time.
The labels JSONB column in organization_configs may lack a consistent schema across organizations, causing deserialization failures or silent missing keys when a new organization is onboarded with a differently structured map.
Mitigation & Contingency
Mitigation: Define and enforce a canonical JSONB schema via a Supabase check constraint and a migration script. Validate the schema in TerminologyRepository at parse time and emit structured errors for any key-type mismatches.
Contingency: If schema drift is discovered post-deployment, LabelKeyResolver's fallback logic ensures the app continues to function with English defaults while a data migration is prepared to normalize the offending organization's config.
Device local storage corruption or platform-specific SharedPreferences serialization bugs could render a cached terminology map unreadable, causing the app to fall back to English defaults unexpectedly for an organization with custom terminology.
Mitigation & Contingency
Mitigation: Wrap all cache reads in try/catch, validate the deserialized map against a minimum-required-keys check, and evict corrupted entries automatically before re-fetching from Supabase.
Contingency: Surface a non-blocking in-app warning to the coordinator that terminology may be in default English until the next sync completes; trigger an immediate background sync.