feat: model undergraduate schools terms and exam queries

This commit is contained in:
Codex
2026-10-14 23:14:48 +08:00
parent 3f28e0a1b6
commit 48367b8273
8 changed files with 176 additions and 27 deletions
@@ -0,0 +1,43 @@
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() {
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);
});
}