Files
English/kouyu_english/test/course_self_consistency_test.dart

88 lines
3.3 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:kouyu_english/core/courses/course_repository.dart';
import 'package:kouyu_english/core/courses/courses.dart';
import 'package:kouyu_english/core/models.dart';
/// Every level goes through the same pack structure and the same rules, so
/// the model answers every pack ships have to pass the rules it ships.
void main() {
setUpAll(() => CourseRepository.instance.load());
tearDownAll(() => CourseRepository.instance.resetForTest());
test('each core item and its dictation sentence pass its own rule', () {
final failures = <String>[];
for (final pack in CourseRepository.instance.units) {
for (final item in pack.coreItems) {
if (item.match.isEmpty) continue;
// A slot like [place] is filled by the learner, so only a fixed
// phrase can be checked as written.
if (!item.en.contains('[') && !matchesRule(item.en, item.match)) {
failures.add('${item.id} en "${item.en}"');
}
if (item.dictationSentence.isNotEmpty &&
!matchesRule(item.dictationSentence, item.match)) {
failures.add('${item.id} dictation "${item.dictationSentence}"');
}
}
}
expect(failures, isEmpty);
});
test('each writing example passes its writing rule', () {
final failures = [
for (final MapEntry(key: id, value: activity)
in segmentActivities.entries)
if (activity.writingExample.isNotEmpty &&
activity.writingRequiredTerms.isNotEmpty &&
!matchesRule(
activity.writingExample,
activity.writingRequiredTerms,
))
'$id "${activity.writingExample}"',
];
expect(failures, isEmpty);
});
test('each dialogue model answer passes its turn', () {
final failures = <String>[];
final dialogues = {
...segmentDialogues,
for (final scene in allScenes) 'scene ${scene.id}': scene.script,
};
for (final MapEntry(key: id, value: script) in dialogues.entries) {
for (var stage = 0; stage < script.hints.length; stage++) {
if (!matchesDialogueStage(script, stage, script.hints[stage])) {
failures.add('$id #${stage + 1} "${script.hints[stage]}"');
}
}
}
expect(failures, isEmpty);
});
test('assessment tasks are answerable and replacements point home', () {
final ids = {for (final pack in assessmentPacks) pack.id};
final failures = <String>[];
for (final pack in assessmentPacks) {
if (pack.replaces != null && !ids.contains(pack.replaces)) {
failures.add('${pack.id} replaces missing ${pack.replaces}');
}
for (final task in pack.tasks) {
final open =
task.skill == AssessmentSkill.writing ||
task.skill == AssessmentSkill.speaking;
if (open) {
if (task.accept.isEmpty) failures.add('${task.id} has no accept');
if (task.guide.isEmpty) failures.add('${task.id} has no guide');
} else {
final index = task.answerIndex;
if (index == null || index < 0 || index >= task.choices.length) {
failures.add('${task.id} answerIndex out of range');
}
}
}
}
expect(a0AssessmentPacks, isNotEmpty);
expect(failures, isEmpty);
});
}