import 'package:flutter_test/flutter_test.dart'; import 'package:kouyu_english/core/courses/courses.dart'; import 'package:kouyu_english/core/models.dart'; import 'package:kouyu_english/core/review_feedback.dart'; ReviewItem review(String id, String target) => ReviewItem( id: id, target: target, prompt: 'Test prompt', hint: target, dueAt: DateTime(2026), skill: '回忆表达', ); void main() { test('does not accept unrelated English for a core phrase', () { final result = ReviewFeedback.check( review('A0-P12', "I'm from [place]."), 'I like tea.', ); expect(result.complete, isFalse); }); test('accepts a new place in the from pattern', () { final result = ReviewFeedback.check( review('A0-P12', "I'm from [place]."), "I'm from Guangzhou.", ); expect(result.complete, isTrue); }); test('checks an A0 word without accepting a different word', () { expect( ReviewFeedback.check(review('A0-W04', 'three'), 'four').complete, isFalse, ); expect( ReviewFeedback.check(review('A0-W04', 'three'), 'three').complete, isTrue, ); }); test('A0-P17 accepts standard o clock expressions', () { expect( ReviewFeedback.check( review('A0-P17', "It's [hour] o'clock."), "It's three o'clock.", ).complete, isTrue, ); expect( ReviewFeedback.check( review('A0-P17', "It's [hour] o'clock."), 'It is two o’clock.', ).complete, isTrue, ); expect( ReviewFeedback.check( review('A0-P17', "It's [hour] o'clock."), 'It is five oclock.', ).complete, isTrue, ); }); test('A0-P20 accepts please say that again and please speak slowly', () { expect( ReviewFeedback.check( review('A0-P20', 'Please say that again.'), 'Please say that again.', ).complete, isTrue, ); expect( ReviewFeedback.check( review('A0-P20', 'Please say that again.'), 'Please speak slowly.', ).complete, isTrue, ); }); test('ignores multiple spaces and casing across review items', () { // Multi-space and uppercase on A0-P03 expect( ReviewFeedback.check( review('A0-P03', 'Nice to meet you.'), ' NICE TO MEET YOU! ', ).complete, isTrue, ); // Multi-space and uppercase on A0-P08 expect( ReviewFeedback.check( review('A0-P08', 'My number is ...'), 'MY NUMBER IS ONE TWO THREE', ).complete, isTrue, ); // Multi-space on word item expect( ReviewFeedback.check(review('A0-W04', 'three'), ' THREE ').complete, isTrue, ); }); test('a dictation review needs the whole sentence that was played', () { final item = review('A0-W24', 'water').copyWith( skill: dictationSkill, prompt: coreReviewVariant('A0-W24', 1).prompt, ); expect(ReviewFeedback.check(item, 'water').complete, isFalse); expect(ReviewFeedback.check(item, 'I like watter.').complete, isFalse); expect(ReviewFeedback.check(item, 'i like water').complete, isTrue); }); test('offline review variants rotate recall, dictation and speaking', () { expect(coreReviewVariant('A0-P12', 0).skill, '回忆表达'); expect(coreReviewVariant('A0-P12', 1).skill, dictationSkill); expect(coreReviewVariant('A0-P12', 2).skill, spokenRecallSkill); expect(coreReviewVariant('A0-P12', 3).skill, '回忆表达'); for (final id in a0CoreItems.keys) { final sentence = coreDictationSentences[id]; expect(sentence, isNotNull, reason: id); // Each dictation sentence really contains the item it checks. expect(coreItemUsedIn(id, sentence!.sentence), isTrue, reason: id); } }); }