import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:hepan_everyday/features/school/school_page_adapter.dart'; import 'package:hepan_everyday/features/school/school_navigation_policy.dart'; import 'package:hepan_everyday/data/schedule_file_import.dart'; import 'package:hepan_everyday/domain/course.dart'; import 'recognized_timetable_test.dart' show fixture; void main() { final target = Uri.parse( 'https://yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/1', ); test('in-flight read cannot authorize a different origin', () async { final reader = SchoolReader(SchoolPageAdapter()), body = Completer(); final valid = reader.read(target, () => body.future); final rejected = reader.read( Uri.parse('https://evil.example/pyxx/pygl/xskbcx/index/1'), () async => fixture(), ); body.complete(fixture()); await expectLater(rejected, throwsA(isA())); await valid; }); test('invalidated read cannot become a fresh authenticated draft', () async { final reader = SchoolReader(SchoolPageAdapter()), body = Completer(); final stale = reader.read(target, () => body.future); final check = expectLater(stale, throwsA(isA())); reader.invalidate(); final fresh = await reader.read(target, () async => fixture()); body.complete(fixture()); await check; expect(fresh.courses.length, 4); expect(reader.busy, isFalse); }); test('official numeric semester routes are allowed but alternate endpoints are not', () { expect( SchoolNavigationPolicy.isTimetable( Uri.parse('https://yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/73'), ), isTrue, ); for (final url in [ 'http://yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/1', 'https://user@yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/1', 'https://yjsjy.uestc.edu.cn:444/pyxx/pygl/xskbcx/index/1', 'https://yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/73/other', 'https://yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/73evil', ]) { expect(SchoolNavigationPolicy.isTimetable(Uri.parse(url)), isFalse); } }); test('BOM saved HTML file imports without claiming live authentication', () { final draft = ScheduleFileImport.parse('\uFEFF${fixture()}'); expect(draft.courses.length, 4); expect(draft.semesterLabel, '2026-2027秋'); expect(draft.source, CourseSource.file); expect(draft.courses.every((c) => c.source == CourseSource.file), isTrue); expect( () => ScheduleFileImport.parse('登录'), throwsA(isA()), ); }); }