Spaces:
Running
Running
Sync from GitHub b098d17dbed1a6386c212d28b4bfa6138ad59d75 (part 2)
Browse files- streamlit_app.py +0 -0
- tests/test_learning_lab_content.py +56 -0
- tests/test_learning_progress_service.py +26 -0
- tests/test_streamlit_routes.py +11 -0
streamlit_app.py
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tests/test_learning_lab_content.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections import Counter
|
| 2 |
+
|
| 3 |
+
from cert_study_app.services.docs_source_service import active_docs_sources, doc_source_by_id
|
| 4 |
+
from cert_study_app.services.learning_lab_service import PRACTICE_TASKS, lessons_for_track, quizzes_for_track
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
ACTIVE_TRACKS = ("linux", "azure", "tool_docs")
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_learning_lab_content_has_no_duplicate_ids():
|
| 11 |
+
lesson_ids = [lesson.id for track in ACTIVE_TRACKS for lesson in lessons_for_track(track)]
|
| 12 |
+
quiz_ids = [quiz.id for track in ACTIVE_TRACKS for quiz in quizzes_for_track(track)]
|
| 13 |
+
practice_ids = [task.id for task in PRACTICE_TASKS]
|
| 14 |
+
|
| 15 |
+
assert [item_id for item_id, count in Counter(lesson_ids).items() if count > 1] == []
|
| 16 |
+
assert [item_id for item_id, count in Counter(quiz_ids).items() if count > 1] == []
|
| 17 |
+
assert [item_id for item_id, count in Counter(practice_ids).items() if count > 1] == []
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def test_learning_lab_content_sources_are_registered():
|
| 21 |
+
source_ids = {
|
| 22 |
+
item.source_id
|
| 23 |
+
for track in ACTIVE_TRACKS
|
| 24 |
+
for item in [*lessons_for_track(track), *quizzes_for_track(track)]
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
assert sorted(source_id for source_id in source_ids if not doc_source_by_id(source_id)) == []
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def test_learning_lab_quizzes_point_to_existing_lessons():
|
| 31 |
+
lesson_ids = {lesson.id for track in ACTIVE_TRACKS for lesson in lessons_for_track(track)}
|
| 32 |
+
|
| 33 |
+
assert sorted(
|
| 34 |
+
quiz.lesson_id
|
| 35 |
+
for track in ACTIVE_TRACKS
|
| 36 |
+
for quiz in quizzes_for_track(track)
|
| 37 |
+
if quiz.lesson_id not in lesson_ids
|
| 38 |
+
) == []
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def test_learning_lab_has_exam_ready_content_volume():
|
| 42 |
+
assert len(lessons_for_track("linux")) >= 50
|
| 43 |
+
assert len(quizzes_for_track("linux")) >= 25
|
| 44 |
+
assert len([task for task in PRACTICE_TASKS if task.track == "linux"]) >= 30
|
| 45 |
+
|
| 46 |
+
assert len(lessons_for_track("azure")) >= 50
|
| 47 |
+
assert len(quizzes_for_track("azure")) >= 25
|
| 48 |
+
|
| 49 |
+
assert len(lessons_for_track("tool_docs")) >= 10
|
| 50 |
+
assert len(quizzes_for_track("tool_docs")) >= 7
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def test_docs_sources_cover_active_tracks():
|
| 54 |
+
assert len(active_docs_sources("azure")) >= 20
|
| 55 |
+
assert len(active_docs_sources("linux")) >= 10
|
| 56 |
+
assert len(active_docs_sources("tool_docs")) >= 4
|
tests/test_learning_progress_service.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import date
|
| 2 |
+
|
| 3 |
+
from cert_study_app.services import learning_progress_service as progress_service
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_learning_progress_migrates_legacy_daily_key(tmp_path, monkeypatch):
|
| 7 |
+
progress_path = tmp_path / "learning_progress.json"
|
| 8 |
+
progress_path.write_text(
|
| 9 |
+
'{"daily": {"2026-06-21": {"tracks": {"linux": {"steps": ["lesson"], "counts": {"lesson": 1}}}}}}',
|
| 10 |
+
encoding="utf-8",
|
| 11 |
+
)
|
| 12 |
+
monkeypatch.setattr(progress_service, "PROGRESS_PATH", progress_path)
|
| 13 |
+
|
| 14 |
+
assert progress_service.completed_steps("linux", date(2026, 6, 21)) == {"lesson"}
|
| 15 |
+
assert progress_service.study_units("linux", date(2026, 6, 21)) == 0.3
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_learning_progress_writes_activity_key(tmp_path, monkeypatch):
|
| 19 |
+
progress_path = tmp_path / "learning_progress.json"
|
| 20 |
+
monkeypatch.setattr(progress_service, "PROGRESS_PATH", progress_path)
|
| 21 |
+
|
| 22 |
+
progress_service.record_activity("linux", "practice", amount=1, target_date=date(2026, 6, 21))
|
| 23 |
+
payload = progress_path.read_text(encoding="utf-8")
|
| 24 |
+
|
| 25 |
+
assert '"activity"' in payload
|
| 26 |
+
assert '"daily"' not in payload
|
tests/test_streamlit_routes.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit_app
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_learning_landing_routes_are_registered():
|
| 5 |
+
routes = streamlit_app.learning_landing_routes()
|
| 6 |
+
|
| 7 |
+
assert routes["๊ฐ๋
๊ณต๋ถ"] == streamlit_app.render_concept_mode_home
|
| 8 |
+
assert routes["๊ฐ๋
๊ณต๋ถ"] == streamlit_app.render_concept_mode_home
|
| 9 |
+
assert routes["์ค์ต"] == streamlit_app.render_practice_mode_home
|
| 10 |
+
assert routes["์ํ์ค๋น"] == streamlit_app.render_exam_prep_home
|
| 11 |
+
assert routes["์ํ ์ค๋น"] == streamlit_app.render_exam_prep_home
|