import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:drift/drift.dart'; import 'package:household_keeper/core/database/database.dart'; import 'package:household_keeper/features/tasks/domain/effort_level.dart'; import 'package:household_keeper/features/tasks/domain/frequency.dart'; void main() { late AppDatabase db; setUp(() { db = AppDatabase(NativeDatabase.memory()); }); tearDown(() async { await db.close(); }); group('RoomsDao', () { test('insertRoom returns a valid id', () async { final id = await db.roomsDao.insertRoom( RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'), ); expect(id, greaterThan(0)); }); test('watchAllRooms emits rooms ordered by sortOrder', () async { // Insert rooms with different sort orders await db.roomsDao.insertRoom( RoomsCompanion.insert( name: 'Badezimmer', iconName: 'bathtub', sortOrder: Value(2), ), ); await db.roomsDao.insertRoom( RoomsCompanion.insert( name: 'Kueche', iconName: 'kitchen', sortOrder: Value(0), ), ); await db.roomsDao.insertRoom( RoomsCompanion.insert( name: 'Schlafzimmer', iconName: 'bed', sortOrder: Value(1), ), ); final rooms = await db.roomsDao.watchAllRooms().first; expect(rooms.length, 3); expect(rooms[0].name, 'Kueche'); expect(rooms[1].name, 'Schlafzimmer'); expect(rooms[2].name, 'Badezimmer'); }); test('updateRoom changes name and iconName', () async { final id = await db.roomsDao.insertRoom( RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'), ); final room = await db.roomsDao.getRoomById(id); final updated = room.copyWith(name: 'Wohnkueche', iconName: 'dining'); await db.roomsDao.updateRoom(updated); final result = await db.roomsDao.getRoomById(id); expect(result.name, 'Wohnkueche'); expect(result.iconName, 'dining'); }); test('deleteRoom cascades to associated tasks and completions', () async { // Create room final roomId = await db.roomsDao.insertRoom( RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'), ); // Create task in the room final taskId = await db.tasksDao.insertTask( TasksCompanion.insert( roomId: roomId, name: 'Abspuelen', intervalType: IntervalType.daily, effortLevel: EffortLevel.low, nextDueDate: DateTime(2026, 3, 15), ), ); // Complete the task to create a completion record await db.tasksDao.completeTask(taskId, now: DateTime(2026, 3, 15)); // Verify task and completion exist final tasksBefore = await db.tasksDao.watchTasksInRoom(roomId).first; expect(tasksBefore.length, 1); // Delete room await db.roomsDao.deleteRoom(roomId); // Verify room is gone final rooms = await db.roomsDao.watchAllRooms().first; expect(rooms, isEmpty); // Verify tasks are gone final tasksAfter = await db.tasksDao.watchTasksInRoom(roomId).first; expect(tasksAfter, isEmpty); }); test('reorderRooms updates sortOrder for all rooms', () async { final id1 = await db.roomsDao.insertRoom( RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'), ); final id2 = await db.roomsDao.insertRoom( RoomsCompanion.insert(name: 'Bad', iconName: 'bathtub'), ); final id3 = await db.roomsDao.insertRoom( RoomsCompanion.insert(name: 'Schlafzimmer', iconName: 'bed'), ); // Reorder: Bad first, then Schlafzimmer, then Kueche await db.roomsDao.reorderRooms([id2, id3, id1]); final rooms = await db.roomsDao.watchAllRooms().first; expect(rooms[0].name, 'Bad'); expect(rooms[1].name, 'Schlafzimmer'); expect(rooms[2].name, 'Kueche'); }); test('watchRoomWithStats emits room with due task count and cleanliness ratio', () async { final roomId = await db.roomsDao.insertRoom( RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'), ); final today = DateTime(2026, 3, 15); // Add a task due today (counts as "due") await db.tasksDao.insertTask( TasksCompanion.insert( roomId: roomId, name: 'Task Due Today', intervalType: IntervalType.daily, effortLevel: EffortLevel.low, nextDueDate: today, ), ); // Add an overdue task (yesterday) await db.tasksDao.insertTask( TasksCompanion.insert( roomId: roomId, name: 'Overdue Task', intervalType: IntervalType.weekly, effortLevel: EffortLevel.medium, nextDueDate: DateTime(2026, 3, 14), ), ); // Add a future task await db.tasksDao.insertTask( TasksCompanion.insert( roomId: roomId, name: 'Future Task', intervalType: IntervalType.monthly, effortLevel: EffortLevel.low, nextDueDate: DateTime(2026, 3, 20), ), ); final stats = await db.roomsDao.watchRoomWithStats(today: today).first; expect(stats.length, 1); final roomStats = stats.first; expect(roomStats.room.name, 'Kueche'); expect(roomStats.totalTasks, 3); // "Due" means on or before today: today (Mar 15) + overdue (Mar 14) = 2 expect(roomStats.dueTasks, 2); // "Overdue" means strictly before today: Mar 14 = 1 expect(roomStats.overdueCount, 1); // Cleanliness: (3 - 1) / 3 = 0.6667 expect(roomStats.cleanlinessRatio, closeTo(0.6667, 0.001)); }); }); }