Files
TPSchedule/mobile/test/widgets/course_length_test.dart
T

150 lines
5.4 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:timezone/data/latest.dart' as tzdata;
import 'package:hepan_everyday/app/app_controller.dart';
import 'package:hepan_everyday/data/file_snapshot_store.dart';
import 'package:hepan_everyday/domain/app_snapshot.dart';
import 'package:hepan_everyday/features/profile/settings_page.dart';
import 'package:hepan_everyday/features/timetable/week_grid.dart';
import 'package:hepan_everyday/domain/schedule_engine.dart';
import '../support/fakes.dart';
import '../domain/schedule_engine_test.dart' show course;
void main() {
setUpAll(tzdata.initializeTimeZones);
test('old saved preferences gain longer default and malformed length is rejected', () {
final old = AppSnapshot().toJson();
(old['settings'] as Map).remove('courseHeightScale');
expect(
(AppSnapshot.fromJson(old).toJson()['settings']
as Map)['courseHeightScale'],
1.25,
);
for (final value in [null, 'long', 0.5, 2.5, double.nan, double.infinity]) {
final json = AppSnapshot().toJson();
(json['settings'] as Map)['courseHeightScale'] = value;
expect(() => AppSnapshot.fromJson(json), throwsFormatException);
}
});
test('custom course length survives an actual disk reload', () async {
final directory = await Directory.systemTemp.createTemp(
'riverside-length-',
);
try {
final json = AppSnapshot().toJson();
(json['settings'] as Map)['courseHeightScale'] = 1.8;
await FileSnapshotStore(directory).save(AppSnapshot.fromJson(json));
final restored = await FileSnapshotStore(directory).load();
expect((restored!.toJson()['settings'] as Map)['courseHeightScale'], 1.8);
} finally {
await directory.delete(recursive: true);
}
});
testWidgets(
'length slider persists across reopening and increases equal-duration bars',
(tester) async {
final store = MemoryStore();
final term = Semester(startDate: DateTime(2026, 9, 7), totalWeeks: 1);
final json = AppSnapshot(
courses: [
course(id: 'A', day: 1, first: 3, last: 4),
course(id: 'B', day: 7, first: 3, last: 4),
],
).toJson();
(json['settings'] as Map)['semester'] = {
'startDate': '2026-09-07',
'totalWeeks': 1,
};
await store.save(AppSnapshot.fromJson(json));
final c = AppController(
store,
FakeNotifications(),
FakeCalendar(),
() => DateTime.utc(2026, 9, 7),
);
await c.initialize();
Future<double> barHeight(AppController controller) async {
final events = ScheduleEngine.occurrences(
controller.snapshot.courses,
term,
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: SingleChildScrollView(
child: WeekGrid(
events: events,
monday: term.firstMonday,
today: term.startDate,
settings: controller.snapshot.settings,
),
),
),
),
);
await tester.pumpAndSettle();
final a = tester.getRect(find.bySemanticsLabel('矩阵论,示例教师,示例教室').first),
b = tester.getRect(find.bySemanticsLabel('矩阵论,示例教师,示例教室').last);
expect(a.height, b.height);
expect(tester.getRect(find.text('周日')).right, lessThanOrEqualTo(800));
return a.height;
}
final before = await barHeight(c);
final alarmsBefore =
(c.notifications as FakeNotifications).reconciliations;
final calendarsBefore = (c.calendar as FakeCalendar).synchronizations;
await tester.pumpWidget(MaterialApp(home: SettingsPage(controller: c)));
await tester.pumpAndSettle();
final slider = find.byKey(const Key('course-height-slider'));
await tester.ensureVisible(slider);
await tester.pumpAndSettle();
final rect = tester.getRect(slider);
await tester.dragFrom(
Offset(rect.left + rect.width * 0.4, rect.center.dy),
Offset(rect.width * 0.4, 0),
);
await tester.pumpAndSettle();
final value =
(c.snapshot.toJson()['settings'] as Map)['courseHeightScale']
as double;
expect(value, greaterThan(1.25));
expect(
(c.notifications as FakeNotifications).reconciliations,
alarmsBefore,
);
expect((c.calendar as FakeCalendar).synchronizations, calendarsBefore);
final restarted = AppController(
store,
FakeNotifications(),
FakeCalendar(),
() => DateTime.utc(2026, 9, 7),
);
await restarted.initialize();
expect(
(restarted.snapshot.toJson()['settings'] as Map)['courseHeightScale'],
value,
);
expect(await barHeight(restarted), greaterThan(before));
await tester.pumpWidget(
MaterialApp(home: SettingsPage(controller: restarted)),
);
await tester.pumpAndSettle();
await tester.ensureVisible(find.text('恢复默认'));
await tester.tap(find.text('恢复默认'));
await tester.pumpAndSettle();
expect(
(restarted.snapshot.toJson()['settings'] as Map)['courseHeightScale'],
1.25,
);
expect(await barHeight(restarted), before);
expect(tester.takeException(), isNull);
c.dispose();
restarted.dispose();
},
);
}