Vocabulary study with FSRS spaced repetition, AI tutoring (Ollama/Claude), essay marking, idioms browser, Anki export, and dashboard. 918 vocabulary entries across 39 categories. 41 tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
87 lines
2.5 KiB
Python
87 lines
2.5 KiB
Python
"""Tests for anki_export.py — Anki .apkg generation."""
|
|
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from anki_export import export_deck
|
|
|
|
SAMPLE_VOCAB = [
|
|
{
|
|
"id": "verb_go",
|
|
"section": "High-frequency language",
|
|
"category": "Common verbs",
|
|
"english": "to go",
|
|
"persian": "رفتن",
|
|
"finglish": "raftan",
|
|
},
|
|
{
|
|
"id": "verb_eat",
|
|
"section": "High-frequency language",
|
|
"category": "Common verbs",
|
|
"english": "to eat",
|
|
"persian": "خوردن",
|
|
"finglish": "khordan",
|
|
},
|
|
{
|
|
"id": "colour_red",
|
|
"section": "High-frequency language",
|
|
"category": "Colours",
|
|
"english": "red",
|
|
"persian": "قرمز",
|
|
"finglish": "ghermez",
|
|
},
|
|
]
|
|
|
|
|
|
def test_export_deck_creates_file(tmp_path):
|
|
"""export_deck should create a valid .apkg file."""
|
|
output = str(tmp_path / "test.apkg")
|
|
result = export_deck(SAMPLE_VOCAB, output_path=output)
|
|
assert result == output
|
|
assert os.path.exists(output)
|
|
assert os.path.getsize(output) > 0
|
|
|
|
|
|
def test_export_deck_is_valid_zip(tmp_path):
|
|
"""An .apkg file is a zip archive containing an Anki SQLite database."""
|
|
output = str(tmp_path / "test.apkg")
|
|
export_deck(SAMPLE_VOCAB, output_path=output)
|
|
assert zipfile.is_zipfile(output)
|
|
|
|
|
|
def test_export_deck_with_category_filter(tmp_path):
|
|
"""export_deck with category filter should only include matching entries."""
|
|
output = str(tmp_path / "test.apkg")
|
|
export_deck(SAMPLE_VOCAB, categories=["Colours"], output_path=output)
|
|
# File should exist and be smaller than unfiltered
|
|
assert os.path.exists(output)
|
|
size_filtered = os.path.getsize(output)
|
|
|
|
output2 = str(tmp_path / "test_all.apkg")
|
|
export_deck(SAMPLE_VOCAB, output_path=output2)
|
|
size_all = os.path.getsize(output2)
|
|
|
|
# Filtered deck should be smaller (fewer cards)
|
|
assert size_filtered <= size_all
|
|
|
|
|
|
def test_export_deck_empty_vocab(tmp_path):
|
|
"""export_deck with empty vocabulary should still create a valid file."""
|
|
output = str(tmp_path / "test.apkg")
|
|
export_deck([], output_path=output)
|
|
assert os.path.exists(output)
|
|
|
|
|
|
def test_export_deck_no_category_match(tmp_path):
|
|
"""export_deck with non-matching category filter should create empty deck."""
|
|
output = str(tmp_path / "test.apkg")
|
|
export_deck(SAMPLE_VOCAB, categories=["Nonexistent"], output_path=output)
|
|
assert os.path.exists(output)
|