import io import wave from pathlib import Path from tutor.domain.models import Attempt, CEFRLevel, Learner from tutor.services.asr.base import FakeASRClient from tutor.services.storage.memory import InMemoryRepository from tutor.services.tts.base import FakeTTSClient def test_cefr_level_ordering() -> None: assert CEFRLevel.A1.rank == 0 assert CEFRLevel.C2.rank == 5 assert CEFRLevel.B1.distance(CEFRLevel.B2) == 1 assert CEFRLevel.A1.distance(CEFRLevel.C2) == 5 async def test_fake_tts_returns_a_valid_wav() -> None: result = await FakeTTSClient().synthesize("Hello world", language="en") assert result.format == "wav" with wave.open(io.BytesIO(result.audio), "rb") as wav: assert wav.getnchannels() == 1 assert wav.getnframes() > 0 async def test_fake_asr_transcribes() -> None: client = FakeASRClient(text="bonjour") transcription = await client.transcribe(Path("/tmp/whatever.wav"), language="fr") assert transcription.text == "bonjour" assert transcription.language == "fr" assert client.calls == [Path("/tmp/whatever.wav")] async def test_memory_repository_roundtrip() -> None: repo = InMemoryRepository() learner = Learner(display_name="Arthur", source_lang="fr", target_lang="en") await repo.save_learner(learner) assert await repo.get_learner(learner.id) == learner assert await repo.get_learner("missing") is None first = Attempt(learner_id=learner.id, exercise_id="ex1", score=0.5) second = Attempt(learner_id=learner.id, exercise_id="ex2", score=1.0) await repo.save_attempt(second) await repo.save_attempt(first) attempts = await repo.list_attempts(learner.id) assert [a.exercise_id for a in attempts] == sorted( [a.exercise_id for a in attempts], key=lambda ex_id: next(a.created_at for a in attempts if a.exercise_id == ex_id), ) assert await repo.list_attempts("missing") == []