118 lines
3.6 KiB
Dart
118 lines
3.6 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:timezone/data/latest.dart' as tzdata;
|
|
import 'package:hepan_everyday/domain/schedule_engine.dart';
|
|
|
|
Course course({
|
|
String id = 'math',
|
|
int day = 3,
|
|
int first = 1,
|
|
int last = 1,
|
|
Set<int> weeks = const {1},
|
|
}) => Course(
|
|
id: id,
|
|
name: '矩阵论',
|
|
teacher: '示例教师',
|
|
room: '示例教室',
|
|
weekday: day,
|
|
startPeriod: first,
|
|
endPeriod: last,
|
|
weeks: weeks,
|
|
source: CourseSource.file,
|
|
);
|
|
|
|
void main() {
|
|
setUpAll(tzdata.initializeTimeZones);
|
|
final term = Semester(startDate: DateTime(2026, 9, 9), totalWeeks: 5);
|
|
test(
|
|
'all eleven lessons produce the specified Shanghai start and end times',
|
|
() {
|
|
const starts = [
|
|
510,
|
|
560,
|
|
620,
|
|
670,
|
|
870,
|
|
920,
|
|
980,
|
|
1030,
|
|
1170,
|
|
1220,
|
|
1270,
|
|
];
|
|
const ends = [555, 605, 665, 715, 915, 965, 1025, 1075, 1215, 1265, 1315];
|
|
for (var p = 1; p <= 11; p++) {
|
|
final result = ScheduleEngine.occurrences([
|
|
course(first: p, last: p),
|
|
], term);
|
|
expect(result, hasLength(1));
|
|
expect(
|
|
result.single.start.hour * 60 + result.single.start.minute,
|
|
starts[p - 1],
|
|
);
|
|
expect(
|
|
result.single.end.hour * 60 + result.single.end.minute,
|
|
ends[p - 1],
|
|
);
|
|
}
|
|
},
|
|
);
|
|
test('term beginning Wednesday suppresses earlier Monday', () {
|
|
expect(
|
|
ScheduleEngine.occurrences([
|
|
course(day: 1, weeks: {1, 2}),
|
|
], term).map((e) => e.start.day).toList(),
|
|
[14],
|
|
);
|
|
expect(ScheduleEngine.weekNumber(term, DateTime(2026, 9, 9)), 1);
|
|
expect(ScheduleEngine.weekNumber(term, DateTime(2026, 9, 14)), 2);
|
|
expect(ScheduleEngine.weekNumber(term, DateTime(2026, 10, 12)), isNull);
|
|
});
|
|
test('odd and nonconsecutive weeks create only matching dates', () {
|
|
expect(
|
|
ScheduleEngine.occurrences([
|
|
course(weeks: {1, 3, 5}),
|
|
], term).map((e) => '${e.start.month}/${e.start.day}').toList(),
|
|
['9/9', '9/23', '10/7'],
|
|
);
|
|
});
|
|
test('Sunday and consecutive periods use one correct occurrence', () {
|
|
final events = ScheduleEngine.occurrences([
|
|
course(day: 7, first: 2, last: 3),
|
|
], term);
|
|
expect(events, hasLength(1));
|
|
expect(events.single.start.day, 13);
|
|
expect(events.single.start.hour, 9);
|
|
expect(events.single.start.minute, 20);
|
|
expect(events.single.end.hour, 11);
|
|
expect(events.single.end.minute, 5);
|
|
});
|
|
test(
|
|
'school lesson time has a fixed UTC instant regardless of device zone',
|
|
() {
|
|
final events = ScheduleEngine.occurrences([course()], term);
|
|
expect(events, hasLength(1));
|
|
expect(events.single.start.toUtc(), DateTime.utc(2026, 9, 9, 0, 30));
|
|
},
|
|
);
|
|
test('overlap keeps simultaneous courses but excludes adjacent courses', () {
|
|
final events = ScheduleEngine.occurrences([
|
|
course(id: 'a', first: 1, last: 2),
|
|
course(id: 'b', first: 2, last: 3),
|
|
course(id: 'c', first: 4, last: 4),
|
|
], term);
|
|
expect(events, hasLength(3));
|
|
expect(ScheduleEngine.overlaps(events[0], events[1]), isTrue);
|
|
expect(ScheduleEngine.overlaps(events[1], events[2]), isFalse);
|
|
});
|
|
test('invalid lesson, weekday and week values are rejected', () {
|
|
expect(() => course(first: 0), throwsArgumentError);
|
|
expect(() => course(last: 13), throwsArgumentError);
|
|
expect(() => course(day: 8), throwsArgumentError);
|
|
expect(() => course(weeks: {0}), throwsArgumentError);
|
|
expect(
|
|
() => Semester(startDate: DateTime(2026), totalWeeks: 31),
|
|
throwsArgumentError,
|
|
);
|
|
});
|
|
}
|