Files
doormile_milderapp/test/stop_compliance_test.dart
Thiru-tenext d7348e253f Miler rider app: surface system, visible design language, backend lifecycle
Design system
- MilerSurface ladder (canvas → working → raised → floating) with MilerPanel
  as layer 1; canvas moved to #DEE3EA so white separates at 1.290:1.
- Visible vocabulary applied across Home, Deliveries, Activity, Account and
  the sheets: hero heads (tabular numeral + small caption, clamped at 1.3x),
  canvas wells for anything that opens, small filled tags for shelf labels,
  demoted placeholders. Recorded in DESIGN_SYSTEM.md §6.
- One icon family: 222 Material glyphs migrated to Lucide; none left outside
  lib/xpress.
- Colour semantics corrected: amber only for what is genuinely owed, brand red
  reserved for the live stop, disabled primaries go neutral rather than pale.

Data and lifecycle
- lib/data/lifecycle.dart reads mutations for what they prove; route_order.dart
  makes admin sequence the single ordering authority; service_day.dart, and
  stop_area.dart rewritten against live Coimbatore addresses (digit-token
  stripping, city stoplist, street suffixes, stammer collapse).
- countLabel states the load once, in bags.

Testing
- 1440 tests passing; golden shot harnesses for Home, Deliveries, Activity,
  sheets and verify, with test/failures/ now gitignored (diff debris).
- New pins: home_gutter_test, stop_area_test, plus updated structural bounds.

Note: this commit also carries pre-existing working-tree deletions that were
present before this work (API_SPEC.md, README.md, demo test fixtures).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 05:40:35 +05:30

121 lines
3.9 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:miler/data/stop_compliance.dart';
/// The two verdicts the hub pays on. Both were already being measured — the
/// bonus rule is "before the ETA" and the distance is measured to bill rider
/// charges — and neither reached the rider until now, so the arithmetic behind
/// them is worth pinning.
void main() {
group('one stop', () {
test('on time and within the route tolerance is clean', () {
const c = StopCompliance(onTime: true, actualKm: 5.4, plannedKm: 5.0);
expect(c.onRoute, isTrue);
expect(c.isClean, isTrue);
expect(c.extraKm, isNull);
});
test('a wander past the tolerance is off route, and says by how much', () {
const c = StopCompliance(onTime: true, actualKm: 12.0, plannedKm: 5.0);
expect(c.onRoute, isFalse);
expect(c.extraKm, 7.0);
expect(c.isClean, isFalse, reason: 'both halves have to hold');
});
// Traffic, one-ways and diversions are the rider's normal, not a detour.
test('ordinary slack does not count as leaving the route', () {
const near = StopCompliance(actualKm: 6.2, plannedKm: 5.0); // +24%
expect(near.onRoute, isTrue);
const grace = StopCompliance(actualKm: 1.4, plannedKm: 1.0); // short hop
expect(
grace.onRoute,
isTrue,
reason: 'a fixed grace keeps short stops from failing on rounding',
);
});
test('late is not clean, however good the route', () {
const c = StopCompliance(
onTime: false,
lateBy: Duration(minutes: 9),
actualKm: 4.0,
plannedKm: 5.0,
);
expect(c.onRoute, isTrue);
expect(c.isClean, isFalse);
});
// A hub that set no ETA, a GPS that never resolved: not the rider's fault
// and never shown as a miss.
test('missing inputs are unknown, not failures', () {
const nothing = StopCompliance();
expect(nothing.isUnknown, isTrue);
expect(nothing.onRoute, isNull);
expect(nothing.isClean, isFalse);
const zeroPlan = StopCompliance(actualKm: 3.0, plannedKm: 0);
expect(
zeroPlan.onRoute,
isNull,
reason: 'a planned distance of zero is missing, not perfect',
);
});
});
group('reading a stored stop', () {
test('prefers the stamp written at completion', () {
final c = StopCompliance.of({
'compliance': {
'ontime': true,
'latebyseconds': 0,
'actualkm': 4.0,
'plannedkm': 4.0,
},
'riderkms': '99',
'kms': '1',
});
expect(c.onTime, isTrue);
expect(c.actualKm, 4.0);
expect(c.onRoute, isTrue);
});
test('falls back to the backend row when there is no stamp', () {
final c = StopCompliance.of({'riderkms': '9.0', 'kms': '4'});
expect(c.onTime, isNull);
expect(c.onRoute, isFalse, reason: '9km against a 4km plan is a wander');
});
});
group('the day', () {
test('scores only what could be measured', () {
final summary = ComplianceSummary.from([
{
'compliance': {'ontime': true, 'actualkm': 4.0, 'plannedkm': 4.0},
},
{
'compliance': {'ontime': false, 'actualkm': 4.0, 'plannedkm': 4.0},
},
{
'compliance': {'ontime': true, 'actualkm': 20.0, 'plannedkm': 4.0},
},
{'orderid': 'no-data'},
]);
expect(summary.measured, 3);
expect(summary.unmeasured, 1, reason: 'and it is not in the denominator');
expect(summary.onTime, 2);
expect(summary.onRoute, 2);
expect(summary.clean, 1);
expect(summary.points, 1, reason: 'a point per stop that cleared both');
expect(summary.onTimePercent, 67);
});
test('an empty day scores nothing rather than dividing by zero', () {
final summary = ComplianceSummary.from(const []);
expect(summary.points, 0);
expect(summary.onTimePercent, 0);
expect(summary.cleanPercent, 0);
});
});
}