Files
Tirsvad f45d6036e4 MIL-008: Choose level
Review record RC-041 (Go, autonomous mode, not independent).

Task: MIL-008#1
Task: MIL-008#2
Task: MIL-008#3
Task: MIL-008#4
Task: MIL-008#5
Task: MIL-008#6
Task: MIL-008#7
Task: MIL-008#8
2026-10-14 23:58:31 +08:00

169 lines
4.8 KiB
Python

"""Tests of the open_study_session use case."""
from collections.abc import Sequence
import pytest
from flash_card.application.dto.card_dto import CardDto
from flash_card.application.use_cases.open_study_session import open_study_session
from flash_card.domain.entities.card import Card
from flash_card.domain.entities.deck import Deck
from flash_card.domain.entities.vocabulary import Vocabulary
from flash_card.domain.errors.vocabulary_errors import VocabularyNotFoundError
from flash_card.domain.value_objects.language_pair import LanguagePair
from flash_card.domain.value_objects.level import Level
class _FakeRepository:
def __init__(self, vocabulary: Vocabulary) -> None:
self._vocabulary = vocabulary
def load(self) -> Vocabulary:
return self._vocabulary
class _RecordingProgress:
def __init__(self, stored: Deck | None = None) -> None:
self.stored = stored
self.saved: list[tuple[Card, ...]] = []
def load(self) -> Deck | None:
return self.stored
def save(self, deck: Deck) -> None:
self.saved.append(deck.cards)
class _SilentSpeech:
def speak(self, text: str, language_code: str) -> None:
return None
class _MissingRepository:
def load(self) -> Vocabulary:
raise VocabularyNotFoundError("missing")
def _first(cards: Sequence[Card]) -> Card:
return cards[0]
def test_open_study_session_builds_session_over_all_cards() -> None:
cards = (Card("aku", "mig"), Card("kau", "du"))
repository = _FakeRepository(Vocabulary(LanguagePair("ms", "da"), cards))
session = open_study_session(
repository, _RecordingProgress(), _SilentSpeech(), _first, Level(None)
)
assert session.remaining == 2
assert session.next_card() == CardDto("aku", "mig", "ms", "da")
def test_open_study_session_propagates_repository_error() -> None:
with pytest.raises(VocabularyNotFoundError):
open_study_session(
_MissingRepository(),
_RecordingProgress(),
_SilentSpeech(),
_first,
Level(None),
)
def test_open_study_session_prefers_saved_progress() -> None:
pair = LanguagePair("ms", "da")
vocabulary = Vocabulary(pair, (Card("aku", "mig"), Card("kau", "du")))
progress = _RecordingProgress(Deck(pair, [Card("kau", "du")]))
session = open_study_session(
_FakeRepository(vocabulary), progress, _SilentSpeech(), _first, Level(None)
)
assert session.remaining == 1
assert session.next_card() == CardDto("kau", "du", "ms", "da")
PAIR = LanguagePair("ms", "da")
THREE = (Card("aku", "mig"), Card("kau", "du"), Card("ini", "denne"))
def _last(cards: Sequence[Card]) -> Card:
return cards[-1]
def test_open_study_session_propagates_error_when_list_is_missing() -> None:
progress = _RecordingProgress(Deck(PAIR, []))
with pytest.raises(VocabularyNotFoundError):
open_study_session(
_MissingRepository(), progress, _SilentSpeech(), _first, Level(None)
)
def test_open_study_session_limits_draws_to_first_cards_of_level() -> None:
session = open_study_session(
_FakeRepository(Vocabulary(PAIR, THREE)),
_RecordingProgress(),
_SilentSpeech(),
_last,
Level(2),
)
assert session.remaining == 3
assert session.remaining_in_level == 2
assert session.next_card() == CardDto("kau", "du", "ms", "da")
def test_open_study_session_uses_vocabulary_order_with_saved_progress() -> None:
progress = _RecordingProgress(Deck(PAIR, [THREE[2], THREE[1]]))
session = open_study_session(
_FakeRepository(Vocabulary(PAIR, THREE)),
progress,
_SilentSpeech(),
_first,
Level(2),
)
assert session.remaining == 2
assert session.remaining_in_level == 1
assert session.next_card() == CardDto("kau", "du", "ms", "da")
def test_open_study_session_is_finished_when_level_has_nothing_left() -> None:
progress = _RecordingProgress(Deck(PAIR, [THREE[1]]))
session = open_study_session(
_FakeRepository(Vocabulary(PAIR, THREE)),
progress,
_SilentSpeech(),
_first,
Level(1),
)
assert session.next_card() is None
assert session.remaining == 1
def test_open_study_session_uses_all_cards_when_level_exceeds_list() -> None:
session = open_study_session(
_FakeRepository(Vocabulary(PAIR, THREE)),
_RecordingProgress(),
_SilentSpeech(),
_first,
Level(1000),
)
assert session.remaining_in_level == 3
def test_open_study_session_never_saves_on_start() -> None:
vocabulary = Vocabulary(LanguagePair("ms", "da"), (Card("aku", "mig"),))
progress = _RecordingProgress()
session = open_study_session(
_FakeRepository(vocabulary), progress, _SilentSpeech(), _first, Level(None)
)
session.next_card()
assert progress.saved == []