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
101 lines
3.0 KiB
Python
101 lines
3.0 KiB
Python
"""Integration tests of saving and resuming progress over real CSV files."""
|
|
|
|
from collections.abc import Callable, Sequence
|
|
from pathlib import Path
|
|
|
|
from flash_card.application.use_cases.open_study_session import open_study_session
|
|
from flash_card.application.use_cases.study_session import StudySession
|
|
from flash_card.domain.entities.card import Card
|
|
from flash_card.domain.value_objects.level import Level
|
|
from flash_card.infrastructure.persistence.csv_progress_repository import (
|
|
CsvProgressRepository,
|
|
)
|
|
from flash_card.infrastructure.persistence.csv_vocabulary_repository import (
|
|
CsvVocabularyRepository,
|
|
)
|
|
from flash_card.infrastructure.speech.null_speech import NullSpeech
|
|
|
|
WORDS = "fr;en\nchaque;each\nparlé;speak\narrivé;come\n"
|
|
|
|
Choose = Callable[[Sequence[Card]], Card]
|
|
|
|
|
|
def _first(cards: Sequence[Card]) -> Card:
|
|
return cards[0]
|
|
|
|
|
|
def _choose_front(front: str) -> Choose:
|
|
def choose(cards: Sequence[Card]) -> Card:
|
|
return next(card for card in cards if card.front == front)
|
|
|
|
return choose
|
|
|
|
|
|
def _open(folder: Path, choose: Choose = _first) -> StudySession:
|
|
return open_study_session(
|
|
CsvVocabularyRepository(folder / "words.csv"),
|
|
CsvProgressRepository(folder / "words_to_learn.csv"),
|
|
NullSpeech(),
|
|
choose,
|
|
Level(None),
|
|
)
|
|
|
|
|
|
def _setup(folder: Path) -> Path:
|
|
(folder / "words.csv").write_text(WORDS, encoding="utf-8")
|
|
return folder / "words_to_learn.csv"
|
|
|
|
|
|
def _text(path: Path) -> str:
|
|
return path.read_bytes().decode("utf-8-sig")
|
|
|
|
|
|
def test_mark_known_writes_remaining_cards_in_order(tmp_path: Path) -> None:
|
|
progress = _setup(tmp_path)
|
|
session = _open(tmp_path, _choose_front("parlé"))
|
|
session.next_card()
|
|
session.mark_known()
|
|
assert _text(progress) == "fr;en\nchaque;each\narrivé;come\n"
|
|
|
|
|
|
def test_restart_draws_only_from_progress_file(tmp_path: Path) -> None:
|
|
_setup(tmp_path)
|
|
first = _open(tmp_path, _choose_front("parlé"))
|
|
first.next_card()
|
|
first.mark_known()
|
|
|
|
second = _open(tmp_path)
|
|
fronts: set[str] = set()
|
|
for _ in range(6):
|
|
card = second.next_card()
|
|
assert card is not None
|
|
fronts.add(card.front_text)
|
|
|
|
assert second.remaining == 2
|
|
assert fronts == {"chaque", "arrivé"}
|
|
|
|
|
|
def test_progress_file_is_readable_as_vocabulary(tmp_path: Path) -> None:
|
|
progress = _setup(tmp_path)
|
|
session = _open(tmp_path, _choose_front("chaque"))
|
|
session.next_card()
|
|
session.mark_known()
|
|
vocabulary = CsvVocabularyRepository(progress).load()
|
|
assert vocabulary.cards == (Card("parlé", "speak"), Card("arrivé", "come"))
|
|
|
|
|
|
def test_header_only_progress_file_gives_finished_session(tmp_path: Path) -> None:
|
|
progress = _setup(tmp_path)
|
|
progress.write_text("fr;en\n", encoding="utf-8")
|
|
session = _open(tmp_path)
|
|
assert session.remaining == 0
|
|
assert session.next_card() is None
|
|
|
|
|
|
def test_unknown_card_never_creates_progress_file(tmp_path: Path) -> None:
|
|
progress = _setup(tmp_path)
|
|
session = _open(tmp_path)
|
|
session.next_card()
|
|
session.next_card()
|
|
assert not progress.exists()
|