import 'package:flutter_test/flutter_test.dart'; import 'package:metatron_student_erp/core/utils/safe_convert.dart'; import 'package:metatron_student_erp/models/attendance.dart'; import 'package:metatron_student_erp/models/dashboard.dart'; import 'package:metatron_student_erp/models/exam.dart'; import 'package:metatron_student_erp/models/result.dart'; import 'package:metatron_student_erp/models/student.dart'; import 'package:metatron_student_erp/models/timetable.dart'; import 'package:metatron_student_erp/models/user.dart'; void main() { group('SafeConvert Utility Tests', () { test('handles Odoo false, null, and empty values gracefully', () { expect(SafeConvert.toNullableString(false), isNull); expect(SafeConvert.toNullableString(null), isNull); expect(SafeConvert.toNullableString('hello'), 'hello'); expect(SafeConvert.toSafeString(false, 'default'), 'default'); expect(SafeConvert.toNullableInt(false), isNull); expect(SafeConvert.toNullableInt(null), isNull); expect(SafeConvert.toNullableInt(42), 42); expect(SafeConvert.toNullableInt('42'), 42); expect(SafeConvert.toSafeInt(false, 0), 0); expect(SafeConvert.toNullableDouble(false), isNull); expect(SafeConvert.toNullableDouble(null), isNull); expect(SafeConvert.toNullableDouble(85.5), 85.5); expect(SafeConvert.toNullableDouble('85.5'), 85.5); expect(SafeConvert.toSafeDouble(false, 0.0), 0.0); expect(SafeConvert.toSafeBool(false), isFalse); expect(SafeConvert.toSafeBool(true), isTrue); expect(SafeConvert.toSafeBool(null), isFalse); expect(SafeConvert.toSafeBool('true'), isTrue); expect(SafeConvert.toNullableMap(false), isNull); expect(SafeConvert.toNullableMap({'a': 1}), {'a': 1}); expect(SafeConvert.toSafeList(false, (x) => x), isEmpty); expect(SafeConvert.toSafeList([1, 2], (x) => x * 2), [2, 4]); }); }); group('Student Profile Parsing with Odoo false fields', () { test('parses full student profile with mixed false and real values', () { final json = { 'id': 4, 'student_id': 'STU-9999', 'admission_number': 'ADM-9999', 'roll_number': false, // Odoo boolean false 'full_name': 'Demo Student', 'email': false, // Odoo boolean false 'mobile': '9876543210', 'gender': 'male', 'date_of_birth': '2000-01-01', 'status': 'active', 'campus': {'id': 11, 'name': 'Main Campus'}, 'department': false, // Odoo boolean false 'program': {'id': 11, 'name': 'B.Tech CS'}, 'level': false, 'academic_year': {'id': 10, 'name': '2026-2027'}, 'academic_term': {'id': 9, 'name': 'Semester 1'}, 'batch': {'id': 3, 'name': 'Batch 2026'}, 'semester': {'id': 3, 'name': 'Sem 1'}, 'section': {'id': 2, 'name': 'Section A'}, }; final profile = StudentProfile.fromJson(json); expect(profile.id, 4); expect(profile.studentId, 'STU-9999'); expect(profile.admissionNumber, 'ADM-9999'); expect(profile.rollNumber, isNull); // Was false in JSON expect(profile.email, isNull); // Was false in JSON expect(profile.mobile, '9876543210'); expect(profile.fullName, 'Demo Student'); expect(profile.campus?.name, 'Main Campus'); expect(profile.department, isNull); // Was false in JSON expect(profile.program?.name, 'B.Tech CS'); expect(profile.academicYear?.name, '2026-2027'); }); }); group('Attendance Parsing Tests', () { test('parses attendance summary and record lines', () { final json = { 'summary': { 'percentage': 87.5, 'present': 14, 'absent': 2, 'late': 1, 'medical_leave': 0, 'on_duty': 0, }, 'records': [ {'id': 101, 'date': '2026-10-12', 'status': 'present', 'remarks': 'On time'}, {'id': 102, 'date': '2026-10-11', 'status': 'absent'}, {'id': 103, 'date': '2026-10-10', 'status': 'late', 'remarks': 'Bus delay 15 mins'}, ], }; final data = AttendanceData.fromJson(json); expect(data.summary.percentage, 87.5); expect(data.summary.present, 14); expect(data.summary.absent, 2); expect(data.records.length, 3); expect(data.records[0].date, '2026-10-12'); expect(data.records[0].status, 'present'); expect(data.records[0].remarks, 'On time'); expect(data.records[1].status, 'absent'); expect(data.records[1].remarks, ''); expect(data.records[2].status, 'late'); expect(data.records[2].remarks, 'Bus delay 15 mins'); }); test('handles empty or false attendance gracefully', () { final data = AttendanceData.fromJson({ 'summary': false, 'records': false, }); expect(data.summary.percentage, 0.0); expect(data.summary.present, 0); expect(data.records, isEmpty); }); test('parses all attendance status types correctly', () { final records = [ {'id': 1, 'date': '2026-10-01', 'status': 'present'}, {'id': 2, 'date': '2026-10-02', 'status': 'absent'}, {'id': 3, 'date': '2026-10-03', 'status': 'late'}, {'id': 4, 'date': '2026-10-04', 'status': 'medical_leave'}, {'id': 5, 'date': '2026-10-05', 'status': 'on_duty'}, ]; final data = AttendanceData.fromJson({ 'summary': { 'percentage': 80.0, 'present': 1, 'absent': 1, 'late': 1, 'medical_leave': 1, 'on_duty': 1, }, 'records': records, }); expect(data.records.length, 5); expect(data.summary.medicalLeave, 1); expect(data.summary.onDuty, 1); expect(data.records[3].status, 'medical_leave'); expect(data.records[4].status, 'on_duty'); }); }); group('Timetable Parsing Tests', () { test('parses timetable slots with faculty and room', () { final json = { 'id': 1, 'date': '2026-10-13', 'day': 'Tuesday', 'start_time': '09:00 AM', 'end_time': '10:00 AM', 'subject': {'id': 1, 'name': 'Algorithms'}, 'faculty': {'id': 2, 'name': 'Dr. Raman'}, 'room': {'id': 3, 'name': 'Hall A'}, }; final slot = TimetableSlot.fromJson(json); expect(slot.id, 1); expect(slot.day, 'Tuesday'); expect(slot.startTime, '09:00 AM'); expect(slot.subject?.name, 'Algorithms'); expect(slot.faculty?.name, 'Dr. Raman'); expect(slot.room?.name, 'Hall A'); }); test('parses timetable slot with null and false optional fields safely', () { final json = { 'id': 2, 'date': '2026-10-14', 'day': 'Wednesday', 'start_time': '11:00 AM', 'end_time': '12:00 PM', 'subject': null, 'faculty': false, 'room': null, }; final slot = TimetableSlot.fromJson(json); expect(slot.id, 2); expect(slot.date, '2026-10-14'); expect(slot.day, 'Wednesday'); expect(slot.startTime, '11:00 AM'); expect(slot.endTime, '12:00 PM'); expect(slot.subject, isNull); expect(slot.faculty, isNull); expect(slot.room, isNull); }); test('handles empty or malformed timetable payload gracefully', () { final slot = TimetableSlot.fromJson({}); expect(slot.id, 0); expect(slot.date, ''); expect(slot.day, ''); expect(slot.startTime, ''); expect(slot.endTime, ''); expect(slot.subject, isNull); expect(slot.faculty, isNull); expect(slot.room, isNull); }); }); group('Exam and Result Parsing Tests', () { test('parses exam details', () { final json = { 'id': 5, 'name': 'Semester End Exam', 'state': 'scheduled', 'start_date': '2026-12-01', 'end_date': '2026-12-15', 'program': {'id': 1, 'name': 'B.Tech CS'}, }; final exam = Exam.fromJson(json); expect(exam.id, 5); expect(exam.name, 'Semester End Exam'); expect(exam.state, 'scheduled'); expect(exam.startDate, '2026-12-01'); expect(exam.program?.name, 'B.Tech CS'); }); test('parses exam results with breakdown lines', () { final json = { 'id': 10, 'exam': {'id': 5, 'name': 'Midterm Exam'}, 'total_max_marks': 200, 'total_obtained_marks': 175, 'percentage': 87.5, 'grade': 'A', 'status': 'pass', 'published_date': '2026-10-01', 'lines': [ { 'subject': {'id': 1, 'name': 'Mathematics'}, 'max_marks': 100, 'pass_marks': 40, 'obtained_marks': 90, 'percentage': 90.0, 'grade': 'A+', 'status': 'pass', }, { 'subject': {'id': 2, 'name': 'Physics'}, 'max_marks': 100, 'pass_marks': 40, 'obtained_marks': 85, 'percentage': 85.0, 'grade': 'A', 'status': 'pass', } ], }; final result = ExamResult.fromJson(json); expect(result.id, 10); expect(result.exam?.name, 'Midterm Exam'); expect(result.totalMaxMarks, 200.0); expect(result.totalObtainedMarks, 175.0); expect(result.percentage, 87.5); expect(result.grade, 'A'); expect(result.status, 'pass'); expect(result.lines.length, 2); expect(result.lines[0].subject?.name, 'Mathematics'); expect(result.lines[0].obtainedMarks, 90.0); expect(result.lines[1].subject?.name, 'Physics'); }); }); group('Dashboard Parsing Tests', () { test('parses complete dashboard payload', () { final json = { 'student': { 'id': 4, 'full_name': 'Demo Student', 'program': {'id': 11, 'name': 'B.Tech CS'}, }, 'attendance': { 'percentage': 92.0, 'present': 23, 'absent': 2, 'late': 0, 'medical_leave': 0, 'on_duty': 0, }, 'today_timetable': [ { 'id': 1, 'date': '2026-10-13', 'day': 'Tuesday', 'start_time': '09:00 AM', 'end_time': '10:00 AM', 'subject': {'id': 1, 'name': 'Operating Systems'}, 'faculty': {'id': 2, 'name': 'Prof. Kumar'}, 'room': {'id': 3, 'name': 'Lab 2'}, } ], 'upcoming_exams': [ { 'id': 1, 'name': 'Midterm Assessment', 'state': 'scheduled', 'start_date': '2026-11-01', } ], 'recent_results': [ { 'id': 1, 'exam': {'id': 1, 'name': 'Unit Test 1'}, 'percentage': 88.0, 'grade': 'A', 'status': 'pass', } ], 'announcements': [ { 'id': 1, 'name': 'College Symposium', 'date': '2026-10-20', 'summary': 'Annual tech symposium registrations open.', } ], }; final dashboard = DashboardData.fromJson(json); expect(dashboard.student?.fullName, 'Demo Student'); expect(dashboard.attendance.percentage, 92.0); expect(dashboard.todayTimetable.length, 1); expect(dashboard.todayTimetable[0].subject?.name, 'Operating Systems'); expect(dashboard.upcomingExams.length, 1); expect(dashboard.upcomingExams[0].name, 'Midterm Assessment'); expect(dashboard.recentResults.length, 1); expect(dashboard.recentResults[0].status, 'pass'); expect(dashboard.announcements.length, 1); expect(dashboard.announcements[0].name, 'College Symposium'); }); }); group('User Model Tests', () { test('parses student and non-student users', () { final studentUser = User.fromJson({ 'id': 1, 'name': 'Demo Student', 'email': 'demo.student', 'role': 'student', }); expect(studentUser.isStudent, isTrue); final adminUser = User.fromJson({ 'id': 2, 'name': 'Admin User', 'email': 'admin', 'role': 'user', }); expect(adminUser.isStudent, isFalse); }); }); }