import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:timezone/data/latest.dart' as tzdata; import 'package:hepan_everyday/features/timetable/week_grid.dart'; import 'package:hepan_everyday/domain/schedule_engine.dart'; import 'package:hepan_everyday/domain/app_settings.dart'; void main() { setUpAll(tzdata.initializeTimeZones); testWidgets( 'conflicts keep readable full-width metadata without covering courses', (tester) async { tester.view.physicalSize = const Size(320, 800); tester.view.devicePixelRatio = 1; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); final term = Semester(startDate: DateTime(2026, 9, 7), totalWeeks: 1); final courses = List.generate( 5, (i) => Course( id: '$i', name: '并行课程$i', teacher: '示例教师$i', room: '示例教学楼B10$i', weekday: 1, startPeriod: 1, endPeriod: 2, weeks: {1}, source: CourseSource.file, ), ); final events = ScheduleEngine.occurrences(courses, term); await tester.pumpWidget( MaterialApp( home: MediaQuery( data: MediaQueryData(textScaler: TextScaler.linear(2)), child: Scaffold( body: SingleChildScrollView( child: WeekGrid( events: events, monday: term.firstMonday, today: term.startDate, settings: AppSettings(), ), ), ), ), ), ); await tester.pumpAndSettle(); expect(find.text('冲突列表'), findsOneWidget); expect(find.text('1–2节'), findsNWidgets(5)); final rects = []; for (final c in courses) { final card = tester.getRect( find.bySemanticsLabel('${c.name},${c.teacher},${c.room}'), ); rects.add(card); expect(card.width, greaterThan(30)); for (final text in [c.teacher, c.room]) { final finder = find.text(text); final paragraph = tester.renderObject(finder); for (final box in paragraph.getBoxesForSelection( TextSelection(baseOffset: 0, extentOffset: text.length), )) { expect(box.right, lessThanOrEqualTo(paragraph.size.width + 0.01)); } expect(tester.getRect(finder).bottom, lessThanOrEqualTo(card.bottom)); } } for (var i = 0; i < rects.length; i++) { for (var j = i + 1; j < rects.length; j++) { expect( rects[i].intersect(rects[j]).height, lessThanOrEqualTo(0.01), reason: '${rects[i]} / ${rects[j]}', ); } } expect(tester.takeException(), isNull); }, ); testWidgets( 'a lunch-gap arrangement has the same length as another two-lesson card', (tester) async { final term = Semester(startDate: DateTime(2026, 9, 7), totalWeeks: 1); Course c(String id, int day, int first) => Course( id: id, name: id, teacher: '教师', room: '教室', weekday: day, startPeriod: first, endPeriod: first + 1, weeks: {1}, source: CourseSource.file, ); final events = ScheduleEngine.occurrences([ c('A', 1, 3), c('B', 2, 4), ], term); await tester.pumpWidget( MaterialApp( home: Scaffold( body: SingleChildScrollView( child: WeekGrid( events: events, monday: term.firstMonday, today: term.startDate, settings: AppSettings(), ), ), ), ), ); await tester.pumpAndSettle(); expect( tester.getRect(find.bySemanticsLabel('A,教师,教室')).height, tester.getRect(find.bySemanticsLabel('B,教师,教室')).height, ); }, ); }