high priority low complexity testing pending testing specialist Tier 5

Acceptance Criteria

All test files are placed under `test/features/bufdir/report_period/` and are discovered by `flutter test`.
PeriodPresetService tests: standard grant cycle presets resolve to the correct start/end DateTimeRange for at least 3 different preset types; custom grant cycle input maps to the expected DateTimeRange; an unknown preset ID throws or returns a defined error — whichever the implementation specifies.
PeriodRecordCountService tests: `getCount(orgId, range)` returns the integer returned by the mock repository; `isFuturePeriod(range)` returns true when the range start is after `DateTime.now()` and false otherwise; async exceptions from the repository propagate correctly.
ReportPeriodValidator — boundary rule: valid full-month range returns `ValidationSuccess`; start not on day 1 returns `ValidationFailure(invalidBoundary)`; end not on last day of month returns `ValidationFailure(invalidBoundary)`; start time not midnight returns `ValidationFailure(invalidBoundary)`.
ReportPeriodValidator — empty range rule: range where start == end returns `ValidationFailure(emptyRange)`; range where start is after end returns `ValidationFailure(emptyRange)`; emptyRange is returned before invalidBoundary when both conditions apply.
ReportPeriodValidator — overlap rule: candidate overlapping an existing submitted period returns `ValidationFailure(overlapsExistingReport)` with the correct conflicting period; adjacent (non-overlapping) period returns `ValidationSuccess`; empty submitted list returns `ValidationSuccess`.
All three `reportPeriodValidatorProvider`, `periodPresetServiceProvider`, and `periodRecordCountServiceProvider` initialise without error inside a `ProviderContainer` with mock overrides.
`flutter test --coverage` reports 100% branch coverage on `report_period_validator_impl.dart` and at least 90% on the two service files.
No test uses `sleep()`, `Future.delayed()`, or real network calls — all async is driven by mock futures.

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod (ProviderContainer)
Dart
apis
MockPeriodConfigurationRepository
ProviderContainer.override
data models
DateTimeRange
ReportPeriod
PeriodPreset
performance requirements
All unit tests must complete in under 5 seconds total — no real timers or network calls.
security requirements
Test fixtures must not contain real orgIds or personal data — use placeholder strings like 'test-org-001'.

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

ProviderContainer usage: `final container = ProviderContainer(overrides: [periodConfigurationRepositoryProvider.overrideWithValue(mockRepo)]); addTearDown(container.dispose);`. For `isFuturePeriod` tests that depend on `DateTime.now()`, inject a `Clock` abstraction or use a fixed reference date passed as a parameter — do not let tests depend on wall clock time, as they will become flaky. For overlap boundary tests, construct DateTimeRanges that are exactly adjacent (end of one == start of next) to verify the inclusive/exclusive semantics are correct. Aim for one `expect` per test case for clear failure messages.

Testing Requirements

Use `flutter_test` with `ProviderContainer` for Riverpod integration. Create mock classes manually (or with `package:mocktail` if already in pubspec) for `PeriodConfigurationRepository`. Organise test files as: `period_preset_service_test.dart`, `period_record_count_service_test.dart`, `report_period_validator_impl_test.dart`. Each file should use `group()` blocks per rule/scenario.

Use `setUp()` to construct a fresh `ProviderContainer` for each test to avoid state leakage between tests. Run `flutter test --coverage` and inspect `lcov.info` to verify branch coverage on the validator implementation.

Component
Report Period Validator
service low
Epic Risks (2)
medium impact high prob dependency

Detecting overlap with previously submitted reports requires querying a report history table that may not yet exist or may not have a reliable submitted_at / period_end field, making the validator dependent on an incomplete upstream feature (Bufdir Report History & Audit Log).

Mitigation & Contingency

Mitigation: Define the minimum interface (a single repository method: getSubmittedPeriods(orgId) → List<DateTimeRange>) as an abstract class in this epic. Implement a stub that returns an empty list until the history feature is available, so the validator compiles and passes tests without a real data source.

Contingency: If the history feature is delayed beyond this feature's delivery window, ship the validator with the stub returning an empty list (overlap check disabled) and surface a feature-flag-controlled warning banner explaining that overlap detection will be enabled in a future update.

medium impact medium prob scope

Bufdir's structural requirements for reporting periods (complete calendar months, grant-year span restrictions) may be ambiguous or subject to change, causing the validator to enforce rules that are incorrect or overly restrictive for some organisations.

Mitigation & Contingency

Mitigation: Document the specific Bufdir rules being enforced in the validator's source code as named constants with references to the relevant Bufdir guidelines. Review the rules with at least one coordinator representative before implementation is finalised.

Contingency: Expose a per-org configuration flag (strict_bufdir_validation: bool) in the period configuration repository so that rule enforcement can be relaxed for specific organisations without a code deployment.