122 lines
4.0 KiB
Python
122 lines
4.0 KiB
Python
|
|
"""Tests wiederverwendbare Fähigkeiten-Erwartungen (Progressionsgraph + später Planung)."""
|
||
|
|
from unittest.mock import MagicMock
|
||
|
|
|
||
|
|
from planning_skill_expectations import (
|
||
|
|
SCOPE_PROGRESSION_PATH,
|
||
|
|
SCOPE_PROGRESSION_STAGE,
|
||
|
|
PlanningSkillExpectationInput,
|
||
|
|
apply_expectations_to_target,
|
||
|
|
build_planning_skill_expectations,
|
||
|
|
expectation_input_from_progression_path,
|
||
|
|
expectation_input_from_progression_stage,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class _FakeCursor:
|
||
|
|
def __init__(self, skills):
|
||
|
|
self._skills = skills
|
||
|
|
|
||
|
|
def execute(self, query, params=None):
|
||
|
|
del query
|
||
|
|
if params and len(params) >= 2:
|
||
|
|
needle = str(params[0]).strip("%").lower()
|
||
|
|
exact = str(params[1]).lower()
|
||
|
|
matches = [
|
||
|
|
s
|
||
|
|
for s in self._skills
|
||
|
|
if needle in s["name"].lower() or s["name"].lower() == exact
|
||
|
|
]
|
||
|
|
self._row = matches[0] if matches else None
|
||
|
|
else:
|
||
|
|
self._row = None
|
||
|
|
|
||
|
|
def fetchone(self):
|
||
|
|
return self._row
|
||
|
|
|
||
|
|
|
||
|
|
def _fake_skill_rows():
|
||
|
|
return [
|
||
|
|
(1, "Koordination", 0),
|
||
|
|
(2, "Timing", 0),
|
||
|
|
(3, "Distanz", 0),
|
||
|
|
(4, "Kime", 0),
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
def test_expectation_input_from_progression_stage_merges_sources(monkeypatch):
|
||
|
|
monkeypatch.setattr(
|
||
|
|
"planning_skill_expectations._load_skills_for_text_match",
|
||
|
|
lambda cur: _fake_skill_rows(),
|
||
|
|
)
|
||
|
|
inp = expectation_input_from_progression_stage(
|
||
|
|
goal_query="Kumite Beinarbeit",
|
||
|
|
goal_analysis={
|
||
|
|
"primary_topic": "Kumite",
|
||
|
|
"start_assumption": "gleichförmige Steppbewegung",
|
||
|
|
"target_state": "explosiver Angriff",
|
||
|
|
},
|
||
|
|
resolved_structured={"roadmap_notes": "Kindergruppe"},
|
||
|
|
stage_spec={
|
||
|
|
"learning_goal": "variable Rhythmen",
|
||
|
|
"load_profile": ["timing", "distanz"],
|
||
|
|
"phase": "vertiefung",
|
||
|
|
},
|
||
|
|
semantic_brief_summary={"must_phrases": ["Beinarbeit"], "primary_topic": "Kumite"},
|
||
|
|
major_step={"phase": "vertiefung", "learning_goal": "Major-Ziel"},
|
||
|
|
)
|
||
|
|
assert inp.scope == SCOPE_PROGRESSION_STAGE
|
||
|
|
assert inp.primary_topic == "Kumite"
|
||
|
|
assert inp.start_situation == "gleichförmige Steppbewegung"
|
||
|
|
assert inp.load_profile == ["timing", "distanz"]
|
||
|
|
assert "Beinarbeit" in inp.skill_hints
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_planning_skill_expectations_load_profile_and_text(monkeypatch):
|
||
|
|
monkeypatch.setattr(
|
||
|
|
"planning_skill_expectations._load_skills_for_text_match",
|
||
|
|
lambda cur: _fake_skill_rows(),
|
||
|
|
)
|
||
|
|
cur = _FakeCursor(
|
||
|
|
[
|
||
|
|
{"id": 2, "name": "Timing"},
|
||
|
|
{"id": 3, "name": "Distanz"},
|
||
|
|
]
|
||
|
|
)
|
||
|
|
inp = PlanningSkillExpectationInput(
|
||
|
|
scope=SCOPE_PROGRESSION_STAGE,
|
||
|
|
primary_topic="Kumite",
|
||
|
|
goal_query="Kumite Beinarbeit mit Timing",
|
||
|
|
load_profile=["timing", "distanz"],
|
||
|
|
)
|
||
|
|
exp = build_planning_skill_expectations(cur, inp)
|
||
|
|
assert exp.scope == SCOPE_PROGRESSION_STAGE
|
||
|
|
assert "load_profile" in exp.sources or "text_match" in exp.sources
|
||
|
|
names = {it.skill_name for it in exp.items}
|
||
|
|
assert "Timing" in names or "Distanz" in names
|
||
|
|
assert exp.skill_weights
|
||
|
|
|
||
|
|
|
||
|
|
def test_expectation_input_from_progression_path_scope():
|
||
|
|
inp = expectation_input_from_progression_path(
|
||
|
|
goal_query="Mae Geri Perfektion",
|
||
|
|
goal_analysis={"primary_topic": "Mae Geri"},
|
||
|
|
resolved_structured={"start_situation": "Grundstellung", "target_state": "freier Kick"},
|
||
|
|
)
|
||
|
|
assert inp.scope == SCOPE_PROGRESSION_PATH
|
||
|
|
assert inp.start_situation == "Grundstellung"
|
||
|
|
assert inp.target_state == "freier Kick"
|
||
|
|
|
||
|
|
|
||
|
|
def test_apply_expectations_to_target_noop_without_weights():
|
||
|
|
class _Target:
|
||
|
|
skill_weights = {}
|
||
|
|
|
||
|
|
def to_summary_dict(self, cur):
|
||
|
|
return {}
|
||
|
|
|
||
|
|
target = _Target()
|
||
|
|
from planning_skill_expectations import PlanningSkillExpectations
|
||
|
|
|
||
|
|
empty = PlanningSkillExpectations(scope=SCOPE_PROGRESSION_STAGE, skill_weights={}, items=[], sources=[])
|
||
|
|
assert apply_expectations_to_target(target, empty) is target
|