import pytest from tutor.services.dictation import normalize_words, score_dictation def test_normalize_folds_case_punctuation_contractions_spelling() -> None: assert normalize_words("Hello, World!") == ["hello", "world"] assert normalize_words("I don't know") == ["i", "do", "not", "know"] assert normalize_words("The colour of the centre") == ["the", "color", "of", "the", "center"] def test_perfect_despite_legitimate_variants() -> None: result = score_dictation("I don't like the colour.", "I do not like the color") assert result.is_perfect assert result.wer == 0.0 assert result.substitutions == result.deletions == result.insertions == 0 def test_catches_phonetic_confusion() -> None: result = score_dictation("I saw a sheep on the hill", "I saw a ship on the hill") assert result.substitutions == 1 subs = [(op.ref_word, op.hyp_word) for op in result.ops if op.op == "substitute"] assert subs == [("sheep", "ship")] def test_deletion_and_alignment_order() -> None: result = score_dictation("the quick brown fox jumps", "the quik brown fox") assert result.substitutions == 1 # quick/quik assert result.deletions == 1 # jumps missing assert [op.op for op in result.ops] == ["equal", "substitute", "equal", "equal", "delete"] def test_insertion_is_flagged() -> None: result = score_dictation("the cat sat", "the big cat sat") assert result.insertions == 1 inserted = [op.hyp_word for op in result.ops if op.op == "insert"] assert inserted == ["big"] def test_empty_hypothesis_is_all_deletions() -> None: result = score_dictation("hello world", " ") assert result.wer == 1.0 assert result.deletions == 2 assert all(op.op == "delete" for op in result.ops) def test_empty_reference_raises() -> None: with pytest.raises(ValueError, match="reference is empty"): score_dictation("!!!", "anything") def test_render_feedback_marks_errors() -> None: from tutor.app.main import render_dictation_feedback perfect = render_dictation_feedback(score_dictation("the cat sat", "the cat sat")) assert "100% correct 🎉" in perfect marked = render_dictation_feedback(score_dictation("I saw a sheep", "I saw a ship")) assert "**sheep**" in marked # correct word in bold assert "~~ship~~" in marked # learner's wrong version struck through