shinkan-jinkendo/backend/tests/test_planning_skill_expectations.py
Lars 1e7941f57b
All checks were successful
Deploy Development / deploy (push) Successful in 42s
Test Suite / pytest-backend (push) Successful in 48s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m22s
Enhance Gap Fill Goal Text and Skill Expectations Integration
- Updated `build_gap_fill_goal_text` to include expected skills in the generated text, improving clarity for users.
- Enhanced `_roadmap_gap_snapshot_for_spec` to incorporate skill expectations from the progression stage, enriching the roadmap context.
- Modified `_annotate_roadmap_step` to append skill expectations to the step reasons, providing additional insights.
- Updated tests to verify the inclusion of expected skills in the gap fill goal text.
- Incremented application version to 0.8.215 to reflect these changes.
2026-06-10 07:09:46 +02:00

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