feat(cefr): CEFR level testing and automated gap ingestion engine (Task 15)

This commit is contained in:
Antigravity committed 2026-10-06 15:24:33 +03:00
1 parent 1c3f03a64c
commit 3fae321322
11 files changed
+2926 -10

No files matched your search

+87
View File
@@ -1359,5 +1359,92 @@ def test_phrasal_verb_detector_unit_and_integration():
assert after_data["phrasal_verb"]["library_card"] is not None
def test_cefr_testing_and_gap_ingestion():
# 1. Unauthenticated check
client.cookies.clear()
unauth = client.get("/api/cefr/levels")
assert unauth.status_code == 401
# 2. Authenticated user login
login_res = client.post("/api/login", json={"username": "testadmin", "password": "testpass12345"})
assert login_res.status_code == 200
# 3. Check level summaries
levels_res = client.get("/api/cefr/levels")
assert levels_res.status_code == 200
levels = levels_res.json()["levels"]
assert len(levels) == 4
level_map = {l["level"]: l for l in levels}
assert "A1" in level_map and "A2" in level_map and "B1" in level_map and "B2" in level_map
assert level_map["A1"]["total_questions"] == 40
assert level_map["A2"]["total_questions"] == 40
assert level_map["B1"]["total_questions"] == 40
assert level_map["B2"]["total_questions"] == 40
# 4. Fetch quiz batch
quiz_res = client.get("/api/cefr/quiz?level=A2&count=5")
assert quiz_res.status_code == 200
quiz_data = quiz_res.json()
assert quiz_data["level"] == "A2"
assert len(quiz_data["quiz"]) == 5
q1 = quiz_data["quiz"][0]
assert "id" in q1
assert "sentence" in q1
assert "clue" in q1
assert len(q1["options"]) == 4
# 5. Answer INCORRECTLY -> Automated Gap Ingestion into SRS!
wrong_opt = "__completely_wrong_option__"
ans_wrong = client.post("/api/cefr/answer", json={
"question_id": q1["id"],
"selected_option": wrong_opt
})
assert ans_wrong.status_code == 200
w_data = ans_wrong.json()
assert w_data["correct"] is False
assert w_data["card_created"] is True
assert w_data["card_id"] is not None
assert w_data["correct_option"] != ""
assert w_data["explanation"] != ""
# Verify the card was actually created in vocabulary_cards with state 'learning' and level tag
card_res = client.get(f"/api/cards/{w_data['card_id']}")
assert card_res.status_code == 200
ingested_card = card_res.json()
assert ingested_card["srs_state"] == "learning"
assert "level-a2" in ingested_card["tags"]
assert "cefr-test" in ingested_card["tags"]
# 6. Check that mode='mistakes' returns this question
mistakes_res = client.get("/api/cefr/quiz?level=A2&mode=mistakes")
assert mistakes_res.status_code == 200
m_data = mistakes_res.json()
assert any(q["id"] == q1["id"] for q in m_data["quiz"])
# 7. Now answer CORRECTLY
ans_correct = client.post("/api/cefr/answer", json={
"question_id": q1["id"],
"selected_option": w_data["correct_option"]
})
assert ans_correct.status_code == 200
c_data = ans_correct.json()
assert c_data["correct"] is True
assert c_data["card_created"] is False
# 8. Check level summary reflects mastered count
levels_res2 = client.get("/api/cefr/levels")
l2_map = {l["level"]: l for l in levels_res2.json()["levels"]}
assert l2_map["A2"]["mastered_count"] >= 1
assert l2_map["A2"]["srs_cards_count"] >= 1
# 9. Test level reset
reset_res = client.post("/api/cefr/reset", json={"level": "A2"})
assert reset_res.status_code == 200
levels_res3 = client.get("/api/cefr/levels")
l3_map = {l["level"]: l for l in levels_res3.json()["levels"]}
assert l3_map["A2"]["mastered_count"] == 0