import 'package:flutter_test/flutter_test.dart'; import 'package:hepan_everyday/domain/school_identity.dart'; import 'package:hepan_everyday/domain/school_term.dart'; import 'package:hepan_everyday/domain/undergraduate_exam_query.dart'; import 'package:hepan_everyday/domain/exam_schedule.dart'; import 'package:hepan_everyday/domain/app_snapshot.dart'; import 'package:hepan_everyday/domain/course.dart'; void main() { test( 'optional exam types reject invalid values even in graduate snapshots', () { final saved = ExamSchedule( semesterLabel: '2026秋', termId: '73', records: [const ExamRecord(code: 'A', name: '课程', examTypeId: 99)], ).toJson(); expect(() => ExamSchedule.fromJson(saved), throwsFormatException); }, ); test( 'managed undergraduate identifiers cannot lose their school or term', () { final c = Course( id: 'uestc-undergraduate-523-managed', name: '课程', teacher: '教师', room: '教室', weekday: 1, startPeriod: 1, endPeriod: 2, weeks: {1}, source: CourseSource.school, ); final saved = AppSnapshot( courses: [c], schoolTerm: SchoolTerm(523, school: SupportedSchool.uestcUndergraduate), ).toJson(); expect( () => AppSnapshot.fromJson({ ...saved, 'schoolTerm': {'id': 73}, }), throwsFormatException, ); expect( () => AppSnapshot.fromJson({...saved, 'schoolTerm': null}), throwsFormatException, ); }, ); SchoolTerm under(int id) => SchoolTerm(id, school: SupportedSchool.uestcUndergraduate); test('undergraduate semester labels and final exam URLs', () { expect([483, 503, 523, 543, 563].map((id) => under(id).label).toList(), [ '2025-2026第一学期', '2025-2026第二学期', '2026-2027第一学期', '2026-2027第二学期', '2027-2028第一学期', ]); final query = UndergraduateExamQuery( term: under(523), types: {UndergraduateExamType.finalExam}, ); expect( query.uriFor(UndergraduateExamType.finalExam).toString(), 'https://eams.uestc.edu.cn/eams/stdExamTable!examTable.action?semester.id=523&examType.id=1', ); expect( () => UndergraduateExamQuery(term: under(523), types: {}), throwsArgumentError, ); expect(() => under(504), throwsArgumentError); expect(under(523), isNot(SchoolTerm(523))); expect(() => under(523).examUri, throwsStateError); expect( SchoolTerm.fromJson({'id': 73}).school, SupportedSchool.uestcGraduate, ); expect(SchoolTerm.undergraduateChoices(DateTime(2026, 10)).first.id, 583); }); test( 'undergraduate exam identity retains both types and rejects corruption', () { final schedule = ExamSchedule( semesterLabel: under(523).label, termId: '523', school: SupportedSchool.uestcUndergraduate, requestedExamTypes: {1, 2}, records: [ const ExamRecord(code: 'A', name: '课程', examTypeId: 1), const ExamRecord(code: 'A', name: '课程', examTypeId: 2), ], ); expect(ExamSchedule.fromJson(schedule.toJson()).records, hasLength(2)); expect( () => ExamSchedule.fromJson({ ...schedule.toJson(), 'requestedExamTypes': [], }), throwsFormatException, ); expect( () => ExamSchedule.fromJson({ ...schedule.toJson(), 'schoolId': 'unknown', }), throwsFormatException, ); final old = ExamSchedule( semesterLabel: '2026秋', termId: '73', records: [ const ExamRecord(code: 'A', name: '课程'), const ExamRecord(code: 'A', name: '课程'), ], ); expect(() => ExamSchedule.fromJson(old.toJson()), throwsFormatException); }, ); test( 'snapshots persist school selection and validate period twelve source', () { final course = Course( id: 'under-523-test', name: '课程', teacher: '教师', room: '教室', weekday: 1, startPeriod: 9, endPeriod: 12, weeks: {1}, source: CourseSource.school, courseCode: 'A', notes: '备注', ); final saved = AppSnapshot( selectedSchool: SupportedSchool.uestcUndergraduate, schoolTerm: under(523), courses: [course], ); final round = AppSnapshot.fromJson(saved.toJson()); expect(round.selectedSchool, SupportedSchool.uestcUndergraduate); expect(round.courses.single.notes, '备注'); expect( () => AppSnapshot.fromJson({ ...saved.toJson(), 'schoolTerm': {'id': 73}, }), throwsFormatException, ); expect( () => AppSnapshot.fromJson({ ...saved.toJson(), 'selectedSchoolId': 'unknown', }), throwsFormatException, ); final legacy = AppSnapshot(schoolTerm: SchoolTerm(73)).toJson() ..remove('selectedSchoolId'); expect( AppSnapshot.fromJson(legacy).selectedSchool, SupportedSchool.uestcGraduate, ); }, ); }