import 'package:adhd_scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; void main() { group('V1 lifecycle contracts', () { final now = DateTime(2026, 6, 24, 9); const engine = SchedulingEngine(); test('durable task statuses exclude movement and V2 burnout labels', () { expect(TaskStatus.values, const [ TaskStatus.planned, TaskStatus.active, TaskStatus.completed, TaskStatus.missed, TaskStatus.cancelled, TaskStatus.noLongerRelevant, TaskStatus.backlog, ]); expect(TaskStatus.values.map((status) => status.name), isNot(contains('pushed'))); expect( TaskStatus.values.map((status) => status.name), isNot(contains('skipped')), ); }); test('manual push preserves durable status and records movement metadata', () { final task = Task( id: 'flexible-1', title: 'Clean coffee maker', projectId: 'home', type: TaskType.flexible, status: TaskStatus.planned, durationMinutes: 15, scheduledStart: DateTime(2026, 6, 24, 9), scheduledEnd: DateTime(2026, 6, 24, 9, 15), createdAt: now, updatedAt: now, ); final result = engine.pushFlexibleTaskToNextAvailableSlot( input: SchedulingInput( tasks: [task], window: SchedulingWindow( start: DateTime(2026, 6, 24, 9), end: DateTime(2026, 6, 24, 10), ), ), taskId: task.id, updatedAt: now.add(const Duration(minutes: 1)), ); final pushed = result.tasks.single; expect(pushed.status, TaskStatus.planned); expect(pushed.stats.manuallyPushedCount, 1); expect(result.changes.single.taskId, task.id); expect(result.notices.single.type, SchedulingNoticeType.moved); }); test('burnout skip remains statistics-compatible without a status', () { final task = Task.quickCapture( id: 'task-1', title: 'Fold laundry', createdAt: now, ).copyWith( status: TaskStatus.planned, stats: const TaskStatistics().incrementSkippedDuringBurnout(), ); expect(task.status, TaskStatus.planned); expect(task.stats.skippedDuringBurnoutCount, 1); expect(TaskStatus.values.map((status) => status.name), isNot(contains('skipped'))); }); test( 'critical missed moves to backlog while inflexible missed stays in place', () { final critical = _scheduledRequiredTask( id: 'critical-1', type: TaskType.critical, now: now, ); final inflexible = _scheduledRequiredTask( id: 'inflexible-1', type: TaskType.inflexible, now: now, ); final missedCritical = engine.markMissed(critical, updatedAt: now); final missedInflexible = engine.markMissed(inflexible, updatedAt: now); expect(missedCritical.status, TaskStatus.backlog); expect(missedCritical.scheduledStart, isNull); expect(missedCritical.scheduledEnd, isNull); expect(missedCritical.stats.missedCount, 1); expect(missedCritical.stats.movedToBacklogCount, 1); expect(missedInflexible.status, TaskStatus.missed); expect(missedInflexible.scheduledStart, inflexible.scheduledStart); expect(missedInflexible.scheduledEnd, inflexible.scheduledEnd); expect(missedInflexible.stats.missedCount, 1); expect(missedInflexible.stats.movedToBacklogCount, 0); }); }); } Task _scheduledRequiredTask({ required String id, required TaskType type, required DateTime now, }) { return Task( id: id, title: 'Required task', projectId: 'home', type: type, status: TaskStatus.planned, durationMinutes: 30, scheduledStart: DateTime(2026, 6, 24, 9), scheduledEnd: DateTime(2026, 6, 24, 9, 30), createdAt: now, updatedAt: now, ); }