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 = []; 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 = []; 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 = []; 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); }); }