import 'dart:convert'; import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:hepan_everyday/services/school_page_diagnostic.dart'; import 'package:hepan_everyday/features/school/undergraduate/timetable_adapter.dart'; void main() { final uri = Uri.parse( 'https://eams.uestc.edu.cn/eams/courseTableForStd.action', ); test( 'leading comments do not remove course declarations from the evidence', () { final store = SchoolPageDiagnostic(); addTearDown(store.clear); final source = File('test/fixtures/school/undergraduate-timetable.html') .readAsStringSync() .replaceFirst( 'var unitCount = 12;', '// units; keep this declaration\nvar unitCount = 12;', ) .replaceAll( 'activity = new TaskActivity', '/* course; declaration */activity = new TaskActivity', ); expect( UndergraduateTimetableAdapter.extract(source, uri).courses, hasLength(18), ); store.remember(source, uri); expect( UndergraduateTimetableAdapter.extract( utf8.decode(store.export()!), uri, ).courses, hasLength(18), ); }, ); test('malformed activity and index statements remain malformed in the exported evidence', () { final store = SchoolPageDiagnostic(); addTearDown(store.clear); final fixture = File('test/fixtures/school/undergraduate-timetable.html') .readAsStringSync(); for (final bad in [ fixture.replaceFirst('"教师1"', 'null'), fixture.replaceFirst('2*unitCount+0', 'unknown()'), ]) { expect( () => UndergraduateTimetableAdapter.extract(bad, uri), throwsFormatException, ); store.remember(bad, uri); final output = utf8.decode(store.export()!); expect( () => UndergraduateTimetableAdapter.extract(output, uri), throwsFormatException, ); expect(output, contains(bad.contains('null') ? 'null' : 'unknown()')); } }); test('diagnostic snapshot preserves parser evidence but removes login material and active HTML', () { var now = DateTime.utc(2026, 10, 16, 5); final store = SchoolPageDiagnostic(clock: () => now); final fixture = File('test/fixtures/school/undergraduate-timetable.html') .readAsStringSync(); store.remember( '''$fixture链接''', uri, ); final output = utf8.decode(store.export()!); expect(output, isNot(contains('SECRET'))); expect(output, isNot(contains('onclick'))); expect(output, isNot(contains('evil.test'))); expect(output, contains('Content-Security-Policy')); expect( UndergraduateTimetableAdapter.extract(output, uri).courses, hasLength(18), ); now = now.add(const Duration(minutes: 11)); expect(store.export(), isNull); }); test('only trusted school evidence can be kept and logout clears it', () { final store = SchoolPageDiagnostic(); store.remember('