Files
English/kouyu_english/test/generated_content_test.dart
T

155 lines
4.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter_test/flutter_test.dart';
import 'package:kouyu_english/core/generated_content.dart';
void main() {
const valid = '''{
"schemaVersion":"review-variant-1",
"variantId":"ai-a0-p12-001",
"targetItemId":"A0-P12",
"prompt":"请用英语说你来自哪里。",
"expectedAnswer":"Im from [place]."
}''';
test('accepts a bounded variant for its requested frozen target', () {
final item = decodeGeneratedReviewVariant(
valid,
expectedTargetItemId: 'A0-P12',
);
expect(item, isNotNull);
expect(item!.targetItemId, 'A0-P12');
});
test('rejects an AI variant that changes the target identity', () {
expect(
decodeGeneratedReviewVariant(valid, expectedTargetItemId: 'A0-P01'),
isNull,
);
});
test('rejects unknown schema fields', () {
final invalid = valid.replaceFirst('}', ',"unsafe":"ignore"}');
expect(
decodeGeneratedReviewVariant(invalid, expectedTargetItemId: 'A0-P12'),
isNull,
);
});
const writing = '''{
"schemaVersion":"writing-feedback-1",
"lessonId":"a0-06",
"verdict":"rewrite",
"feedback":"加上 from 就能说清来自哪里。",
"suggestion":"I'm from Hong Kong.",
"missing":["来自哪里"]
}''';
test('accepts bounded writing feedback for its lesson', () {
final feedback = decodeWritingAiFeedback(
writing,
expectedLessonId: 'a0-06',
);
expect(feedback, isNotNull);
expect(feedback!.verdict, 'rewrite');
});
test('rejects writing feedback for a different lesson', () {
expect(decodeWritingAiFeedback(writing, expectedLessonId: 'a0-07'), isNull);
});
const lesson = '''{
"schemaVersion":"lesson-1",
"lessonId":"ai-a0-p12-1",
"revision":1,
"stageVersion":"A0-1.0",
"source":"aiGenerated",
"status":"validated",
"abilityIds":["A0-C06"],
"prerequisiteIds":["a0-05"],
"targetItemIds":["A0-P12"],
"receptiveChunks":[],
"newItemIds":[],
"previewItemIds":[],
"estimatedMinutes":10,
"tasks":[
{"taskId":"l","skill":"listening","type":"listenChoice","prompt":"听后选择。","stimulus":"I am from Hong Kong.","answer":"Hong Kong","targetItemIds":["A0-P12"]},
{"taskId":"s","skill":"speaking","type":"repeat","prompt":"跟读。","stimulus":"I am from Hong Kong.","answer":"I am from Hong Kong.","targetItemIds":["A0-P12"]},
{"taskId":"r","skill":"reading","type":"readAnswer","prompt":"读后回答。","stimulus":"I am from Hong Kong.","answer":"Hong Kong","targetItemIds":["A0-P12"]},
{"taskId":"w","skill":"writing","type":"writeAnswer","prompt":"写一句。","stimulus":"来自香港。","answer":"I am from Hong Kong.","targetItemIds":["A0-P12"]}
]
}''';
test('accepts a bounded four-skill adaptive lesson', () {
final decoded = decodeGeneratedLesson(
lesson,
expectedTargetItemId: 'A0-P12',
);
expect(decoded, isNotNull);
expect(decoded!.tasks.map((task) => task.skill).toSet(), hasLength(4));
});
test('adaptive answer check accepts harmless punctuation variation', () {
final task = decodeGeneratedLesson(
lesson,
expectedTargetItemId: 'A0-P12',
)!.tasks[3];
expect(matchesAdaptiveLessonAnswer(task, "i am from hong kong!"), isTrue);
});
test('adaptive answer check rejects a missing target token', () {
final task = decodeGeneratedLesson(
lesson,
expectedTargetItemId: 'A0-P12',
)!.tasks[3];
expect(matchesAdaptiveLessonAnswer(task, 'I am from Hong.'), isFalse);
});
test('adaptive answer spec accepts listed slots and rejects exclusions', () {
const task = GeneratedLessonTask(
taskId: 'speaking',
skill: 'speaking',
type: 'repeat',
prompt: '说一句。',
stimulus: 'I am from Hong Kong.',
answer: 'I am from Hong Kong.',
targetItemIds: ['A0-P12'],
answerSpec: GeneratedAnswerSpec(
requiredAnyPhrases: [
['I am', "I'm"],
['from'],
['Hong Kong'],
],
acceptedAnswers: ['I am from Hong Kong.', "I'm from Hong Kong."],
forbiddenPhrases: ['Beijing'],
),
);
expect(matchesAdaptiveLessonAnswer(task, "I'm from Hong Kong!"), isTrue);
expect(matchesAdaptiveLessonAnswer(task, 'I am from Beijing.'), isFalse);
expect(matchesAdaptiveLessonAnswer(task, 'Hong Kong.'), isFalse);
});
test('rejects an adaptive lesson with a different frozen target', () {
expect(
decodeGeneratedLesson(lesson, expectedTargetItemId: 'A0-P11'),
isNull,
);
});
test(
'rejects an adaptive lesson that introduces an unknown English word',
() {
final invalid = lesson.replaceFirst('Hong Kong', 'library');
expect(
decodeGeneratedLesson(invalid, expectedTargetItemId: 'A0-P12'),
isNull,
);
},
);
}