focus-flow/test/required_task_actions_test.dart

180 lines
5.1 KiB
Dart

import 'package:adhd_scheduler_core/scheduler_core.dart';
import 'package:test/test.dart';
void main() {
group('Required task action service', () {
final now = DateTime(2026, 6, 19, 12);
const service = RequiredTaskActionService();
test('done marks inflexible task completed without clearing history', () {
final task = requiredTask(
id: 'appointment',
type: TaskType.inflexible,
createdAt: now,
start: DateTime(2026, 6, 19, 9),
);
final result = service.apply(
task: task,
action: RequiredTaskAction.done,
updatedAt: now,
);
expect(result.action, RequiredTaskAction.done);
expect(result.task.status, TaskStatus.completed);
expect(result.task.scheduledStart, task.scheduledStart);
expect(result.task.scheduledEnd, task.scheduledEnd);
expect(result.removedFromActivePlan, isFalse);
});
test('done marks critical task completed without moving it', () {
final task = requiredTask(
id: 'meds',
type: TaskType.critical,
createdAt: now,
start: DateTime(2026, 6, 19, 10),
);
final result = service.apply(
task: task,
action: RequiredTaskAction.done,
updatedAt: now,
);
expect(result.task.status, TaskStatus.completed);
expect(result.task.scheduledStart, task.scheduledStart);
expect(result.task.scheduledEnd, task.scheduledEnd);
});
test('missed critical task moves to backlog and clears schedule', () {
final task = requiredTask(
id: 'critical',
type: TaskType.critical,
createdAt: now,
start: DateTime(2026, 6, 19, 9),
);
final result = service.apply(
task: task,
action: RequiredTaskAction.missed,
updatedAt: now,
);
expect(result.task.status, TaskStatus.backlog);
expect(result.task.scheduledStart, isNull);
expect(result.task.scheduledEnd, isNull);
expect(result.task.stats.missedCount, 1);
expect(result.task.stats.movedToBacklogCount, 1);
expect(result.removedFromActivePlan, isTrue);
});
test('missed inflexible task remains scheduled as history', () {
final task = requiredTask(
id: 'appointment',
type: TaskType.inflexible,
createdAt: now,
start: DateTime(2026, 6, 19, 9),
);
final result = service.apply(
task: task,
action: RequiredTaskAction.missed,
updatedAt: now,
);
expect(result.task.status, TaskStatus.missed);
expect(result.task.scheduledStart, task.scheduledStart);
expect(result.task.scheduledEnd, task.scheduledEnd);
expect(result.task.stats.missedCount, 1);
expect(result.removedFromActivePlan, isFalse);
});
test('cancel and no-longer-relevant remain distinct states', () {
final task = requiredTask(
id: 'appointment',
type: TaskType.inflexible,
createdAt: now,
start: DateTime(2026, 6, 19, 9),
);
final cancelled = service.apply(
task: task,
action: RequiredTaskAction.cancel,
updatedAt: now,
);
final noLongerRelevant = service.apply(
task: task,
action: RequiredTaskAction.noLongerRelevant,
updatedAt: now,
);
expect(cancelled.task.status, TaskStatus.cancelled);
expect(cancelled.task.scheduledStart, isNull);
expect(cancelled.task.scheduledEnd, isNull);
expect(cancelled.task.stats.cancelledCount, 1);
expect(cancelled.removedFromActivePlan, isTrue);
expect(noLongerRelevant.task.status, TaskStatus.noLongerRelevant);
expect(noLongerRelevant.task.scheduledStart, isNull);
expect(noLongerRelevant.task.scheduledEnd, isNull);
expect(noLongerRelevant.task.stats.cancelledCount, 0);
expect(noLongerRelevant.removedFromActivePlan, isTrue);
});
test('required action service rejects flexible tasks', () {
final task = Task.quickCapture(
id: 'flexible',
title: 'Flexible',
createdAt: now,
).copyWith(status: TaskStatus.planned);
expect(
() => service.apply(
task: task,
action: RequiredTaskAction.done,
updatedAt: now,
),
throwsArgumentError,
);
});
test('required action service rejects locked tasks', () {
final task = requiredTask(
id: 'locked',
type: TaskType.locked,
createdAt: now,
start: DateTime(2026, 6, 19, 9),
);
expect(
() => service.apply(
task: task,
action: RequiredTaskAction.missed,
updatedAt: now,
),
throwsArgumentError,
);
});
});
}
Task requiredTask({
required String id,
required TaskType type,
required DateTime createdAt,
required DateTime start,
}) {
return Task(
id: id,
title: id,
projectId: 'required',
type: type,
status: TaskStatus.planned,
priority: PriorityLevel.high,
durationMinutes: 30,
scheduledStart: start,
scheduledEnd: start.add(const Duration(minutes: 30)),
createdAt: createdAt,
updatedAt: createdAt,
);
}