import 'package:focusflow_shared/focusflow_shared.dart'; import 'package:test/test.dart'; void main() { group('Task', () { test('creates with required fields', () { final task = Task( id: 'task-1', userId: 'user-1', title: 'Test task', createdAt: DateTime(2024, 1, 1), ); expect(task.id, 'task-1'); expect(task.title, 'Test task'); expect(task.status, 'pending'); expect(task.priority, 0); expect(task.energyLevel, 'medium'); expect(task.noveltyFactor, 1.0); expect(task.timesPostponed, 0); expect(task.tags, isEmpty); expect(task.version, 1); }); test('serializes to JSON and back', () { final task = Task( id: 'task-1', userId: 'user-1', title: 'Test task', priority: 50, tags: ['focus', 'work'], createdAt: DateTime(2024, 1, 1), ); final json = task.toJson(); final restored = Task.fromJson(json); expect(restored.id, task.id); expect(restored.title, task.title); expect(restored.priority, task.priority); expect(restored.tags, task.tags); }); }); group('Streak', () { test('creates with defaults', () { final streak = Streak( id: 's-1', userId: 'user-1', name: 'Morning routine', createdAt: DateTime(2024, 1, 1), ); expect(streak.streakType, 'daily'); expect(streak.currentCount, 0); expect(streak.graceDays, 2); expect(streak.isActive, true); expect(streak.encouragementShown, false); }); test('serializes to JSON and back', () { final streak = Streak( id: 's-1', userId: 'user-1', name: 'Morning routine', currentCount: 7, longestCount: 14, createdAt: DateTime(2024, 1, 1), ); final json = streak.toJson(); final restored = Streak.fromJson(json); expect(restored.name, streak.name); expect(restored.currentCount, 7); expect(restored.longestCount, 14); }); }); group('User', () { test('creates with defaults', () { final user = User( id: 'u-1', email: 'test@example.com', displayName: 'Test User', createdAt: DateTime(2024, 1, 1), ); expect(user.timezone, 'UTC'); expect(user.onboardingCompleted, false); expect(user.preferredTaskLoad, 5); expect(user.focusSessionMinutes, 25); expect(user.rewardStyle, 'playful'); expect(user.forgivenessEnabled, true); expect(user.subscriptionTier, 'free'); }); }); group('ApiResponse', () { test('creates success response', () { final response = ApiResponse.success('hello'); expect(response.status, 'success'); expect(response.data, 'hello'); expect(response.error, isNull); }); test('creates error response', () { final response = ApiResponse.error('NOT_FOUND', 'Task not found'); expect(response.status, 'error'); expect(response.data, isNull); expect(response.error!.code, 'NOT_FOUND'); expect(response.error!.message, 'Task not found'); }); }); group('TaskValidator', () { test('validates title - empty', () { expect(TaskValidator.validateTitle(null), 'Title is required'); expect(TaskValidator.validateTitle(''), 'Title is required'); expect(TaskValidator.validateTitle(' '), 'Title is required'); }); test('validates title - too long', () { final longTitle = 'x' * 501; expect(TaskValidator.validateTitle(longTitle), 'Title must be 500 characters or less'); }); test('validates title - valid', () { expect(TaskValidator.validateTitle('Buy groceries'), isNull); }); test('validates estimated minutes', () { expect(TaskValidator.validateEstimatedMinutes(null), isNull); expect(TaskValidator.validateEstimatedMinutes(0), 'Estimate must be at least 1 minute'); expect(TaskValidator.validateEstimatedMinutes(481), 'Estimate cannot exceed 8 hours'); expect(TaskValidator.validateEstimatedMinutes(30), isNull); }); test('validates priority', () { expect(TaskValidator.validatePriority(null), isNull); expect(TaskValidator.validatePriority(-1), 'Priority must be 0-100'); expect(TaskValidator.validatePriority(101), 'Priority must be 0-100'); expect(TaskValidator.validatePriority(50), isNull); }); }); group('Enums', () { test('TaskStatus display names', () { expect(TaskStatus.pending.displayName, 'To Do'); expect(TaskStatus.inProgress.displayName, 'In Progress'); expect(TaskStatus.completed.displayName, 'Done'); }); test('TaskStatus API values', () { expect(TaskStatus.pending.apiValue, 'pending'); expect(TaskStatus.inProgress.apiValue, 'in_progress'); }); test('EnergyLevel display names', () { expect(EnergyLevel.low.displayName, 'Low Energy'); expect(EnergyLevel.medium.displayName, 'Medium Energy'); expect(EnergyLevel.high.displayName, 'High Energy'); }); test('RewardType display names', () { expect(RewardType.animation.displayName, 'Celebration'); expect(RewardType.surprise.displayName, 'Surprise!'); }); test('RewardStyle display names', () { expect(RewardStyle.playful.displayName, 'Playful (animations & messages)'); expect(RewardStyle.data.displayName, 'Data-driven (stats & charts)'); }); }); group('ApiConstants', () { test('base path', () { expect(ApiConstants.basePath, '/api/v1'); }); test('task routes', () { expect(ApiConstants.tasks, '/api/v1/tasks'); expect(ApiConstants.task('abc'), '/api/v1/tasks/abc'); expect(ApiConstants.completeTask('abc'), '/api/v1/tasks/abc/complete'); }); test('room routes', () { expect(ApiConstants.rooms, '/api/v1/rooms'); expect(ApiConstants.joinRoom('r1'), '/api/v1/rooms/r1/join'); }); }); group('AppLimits', () { test('free tier limits', () { expect(AppLimits.freeMaxActiveTasks, 15); expect(AppLimits.freeMaxStreaks, 3); }); test('pagination defaults', () { expect(AppLimits.defaultPageSize, 20); expect(AppLimits.maxPageSize, 100); }); }); group('ErrorCodes', () { test('error code values', () { expect(ErrorCodes.taskNotFound, 'TASK_NOT_FOUND'); expect(ErrorCodes.premiumRequired, 'PREMIUM_REQUIRED'); expect(ErrorCodes.rateLimited, 'RATE_LIMITED'); }); }); }