import 'package:adhd_scheduler_core/scheduler_core.dart'; import 'package:test/test.dart'; void main() { group('MongoDB document mapping helpers', () { final createdAt = DateTime.utc(2026, 6, 23, 8); test('task documents round-trip every scheduling field', () { final task = scheduledTask( id: 'task-1', createdAt: createdAt, reward: RewardLevel.high, difficulty: DifficultyLevel.hard, ).copyWith( stats: const TaskStatistics().incrementManualPush(), ); final document = task.toDocument(); final restored = TaskDocumentMapping.fromDocument(document); expect(document[TaskDocumentFields.id], task.id); expect(document[TaskDocumentFields.type], 'flexible'); expect(document[TaskDocumentFields.status], 'planned'); expect(document[TaskDocumentFields.reward], 'high'); expect(document[TaskDocumentFields.difficulty], 'hard'); expect(document[TaskDocumentFields.scheduledStart], '2026-06-23T09:00:00.000Z'); expect(restored.id, task.id); expect(restored.title, task.title); expect(restored.projectId, task.projectId); expect(restored.type, task.type); expect(restored.status, task.status); expect(restored.priority, task.priority); expect(restored.reward, task.reward); expect(restored.difficulty, task.difficulty); expect(restored.durationMinutes, task.durationMinutes); expect(restored.scheduledStart, task.scheduledStart); expect(restored.scheduledEnd, task.scheduledEnd); expect(restored.actualStart, task.actualStart); expect(restored.actualEnd, task.actualEnd); expect(restored.completedAt, task.completedAt); expect(restored.parentTaskId, task.parentTaskId); expect(restored.backlogTags, task.backlogTags); expect(restored.reminderOverride, task.reminderOverride); expect(restored.createdAt, task.createdAt); expect(restored.updatedAt, task.updatedAt); expect(restored.stats.manuallyPushedCount, 1); }); test('task documents preserve not-set reward distinctly from very low', () { final noReward = scheduledTask( id: 'no-reward', createdAt: createdAt, reward: RewardLevel.notSet, ); final veryLowReward = scheduledTask( id: 'very-low', createdAt: createdAt, reward: RewardLevel.veryLow, ); final noRewardDocument = noReward.toDocument(); final veryLowRewardDocument = veryLowReward.toDocument(); expect(noRewardDocument[TaskDocumentFields.reward], 'notSet'); expect(veryLowRewardDocument[TaskDocumentFields.reward], 'veryLow'); expect( TaskDocumentMapping.fromDocument(noRewardDocument).reward, RewardLevel.notSet, ); expect( TaskDocumentMapping.fromDocument(veryLowRewardDocument).reward, RewardLevel.veryLow, ); }); test('task documents support explicit nullable schedule clearing', () { final task = scheduledTask( id: 'scheduled', createdAt: createdAt, ); final clearedDocument = task.toDocument(clearSchedule: true); final restored = TaskDocumentMapping.fromDocument(clearedDocument); expect(clearedDocument[TaskDocumentFields.scheduledStart], isNull); expect(clearedDocument[TaskDocumentFields.scheduledEnd], isNull); expect(restored.scheduledStart, isNull); expect(restored.scheduledEnd, isNull); expect(restored.id, task.id); }); test('task statistics document mapping preserves every counter', () { const stats = TaskStatistics( skippedDuringBurnoutCount: 1, manuallyPushedCount: 2, autoPushedCount: 3, movedToBacklogCount: 4, restoredFromBacklogCount: 5, missedCount: 6, cancelledCount: 7, completedLateCount: 8, completedDuringLockedHoursCount: 9, completedDuringLockedHoursMinutes: 10, completedAfterShieldCount: 11, completedAfterPushCount: 12, totalPushesBeforeCompletion: 13, ); final document = stats.toDocument(); final restored = TaskStatisticsDocumentMapping.fromDocument(document); expect(document.keys.toSet(), TaskStatisticsDocumentFields.all); expect(restored.skippedDuringBurnoutCount, 1); expect(restored.manuallyPushedCount, 2); expect(restored.autoPushedCount, 3); expect(restored.movedToBacklogCount, 4); expect(restored.restoredFromBacklogCount, 5); expect(restored.missedCount, 6); expect(restored.cancelledCount, 7); expect(restored.completedLateCount, 8); expect(restored.completedDuringLockedHoursCount, 9); expect(restored.completedDuringLockedHoursMinutes, 10); expect(restored.completedAfterShieldCount, 11); expect(restored.completedAfterPushCount, 12); expect(restored.totalPushesBeforeCompletion, 13); }); test('project statistics document mapping preserves aggregate fields', () { final statistics = ProjectStatistics( projectId: 'home', completedTaskCount: 8, durationMinuteCounts: const {20: 3, 45: 5}, completionTimeBucketCounts: const { ProjectCompletionTimeBucket.morning: 6, ProjectCompletionTimeBucket.evening: 2, }, totalPushesBeforeCompletion: 11, completedAfterPushCount: 4, rewardCounts: const { RewardLevel.high: 5, RewardLevel.low: 3, }, difficultyCounts: const { DifficultyLevel.easy: 2, DifficultyLevel.hard: 6, }, reminderProfileCounts: const { ReminderProfile.gentle: 3, ReminderProfile.persistent: 5, }, ); final document = statistics.toDocument(); final restored = ProjectStatisticsDocumentMapping.fromDocument(document); expect(document.keys.toSet(), ProjectStatisticsDocumentFields.all); expect(document[ProjectStatisticsDocumentFields.id], 'home'); expect(document[ProjectStatisticsDocumentFields.durationMinuteCounts], { '20': 3, '45': 5, }); expect(restored.projectId, statistics.projectId); expect(restored.completedTaskCount, 8); expect(restored.durationMinuteCounts, statistics.durationMinuteCounts); expect(restored.completionTimeBucketCounts, statistics.completionTimeBucketCounts); expect(restored.totalPushesBeforeCompletion, 11); expect(restored.completedAfterPushCount, 4); expect(restored.rewardCounts, statistics.rewardCounts); expect(restored.difficultyCounts, statistics.difficultyCounts); expect(restored.reminderProfileCounts, statistics.reminderProfileCounts); }); test('enum document mapping rejects unknown persistence names', () { expect( () => PersistenceEnumMapping.decodeTaskType('unknown'), throwsArgumentError, ); }); }); } Task scheduledTask({ required String id, required DateTime createdAt, RewardLevel reward = RewardLevel.notSet, DifficultyLevel difficulty = DifficultyLevel.medium, }) { return Task( id: id, title: 'Scheduled task', projectId: 'project-1', type: TaskType.flexible, status: TaskStatus.planned, priority: PriorityLevel.medium, reward: reward, difficulty: difficulty, durationMinutes: 30, scheduledStart: DateTime.utc(2026, 6, 23, 9), scheduledEnd: DateTime.utc(2026, 6, 23, 9, 30), actualStart: DateTime.utc(2026, 6, 23, 9, 5), actualEnd: DateTime.utc(2026, 6, 23, 9, 25), completedAt: DateTime.utc(2026, 6, 23, 9, 30), parentTaskId: 'parent-1', backlogTags: const {BacklogTag.wishlist}, reminderOverride: ReminderProfile.persistent, createdAt: createdAt, updatedAt: createdAt.add(const Duration(minutes: 5)), ); }