This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/geo-service/tests/test_learning.py
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

195 lines
6.2 KiB
Python

"""
Tests for Learning Generator Service
"""
import pytest
from unittest.mock import patch, MagicMock, AsyncMock
import json
import sys
sys.path.insert(0, '/app')
from services.learning_generator import LearningGeneratorService
from models.learning_node import LearningTheme, NodeType
class TestLearningGeneratorService:
"""Tests for Learning Generator Service."""
@pytest.fixture
def service(self):
"""Create service instance."""
return LearningGeneratorService()
def test_build_generation_prompt_topographie(self, service):
"""Test prompt building for topography theme."""
aoi_info = {
"bounds": {"west": 9.18, "south": 47.70, "east": 9.20, "north": 47.72},
"center": {"latitude": 47.71, "longitude": 9.19},
"area_km2": 0.5,
}
prompt = service._build_generation_prompt(
aoi_info=aoi_info,
theme=LearningTheme.TOPOGRAPHIE,
difficulty="mittel",
node_count=5,
grade_level="7-8",
language="de",
)
assert "Topographie" in prompt or "topographie" in prompt
assert "47.71" in prompt # center latitude
assert "9.19" in prompt # center longitude
assert "5" in prompt # node count
assert "mittel" in prompt # difficulty
assert "7-8" in prompt # grade level
assert "JSON" in prompt
def test_build_generation_prompt_landnutzung(self, service):
"""Test prompt building for land use theme."""
aoi_info = {
"bounds": {"west": 9.18, "south": 47.70, "east": 9.20, "north": 47.72},
"center": {"latitude": 47.71, "longitude": 9.19},
"area_km2": 0.5,
}
prompt = service._build_generation_prompt(
aoi_info=aoi_info,
theme=LearningTheme.LANDNUTZUNG,
difficulty="leicht",
node_count=3,
grade_level=None,
language="de",
)
assert "Landnutzung" in prompt or "landnutzung" in prompt
def test_parse_llm_response_valid(self, service):
"""Test parsing valid LLM response."""
response = """
Here are the learning nodes:
[
{
"title": "Höhenbestimmung",
"position": {"latitude": 47.71, "longitude": 9.19},
"question": "Schätze die Höhe dieses Punktes.",
"hints": ["Schau auf die Vegetation", "Vergleiche mit dem See"],
"answer": "Ca. 500m",
"explanation": "Die Höhe lässt sich...",
"node_type": "question",
"points": 10
}
]
"""
nodes = service._parse_llm_response(
response, "test-aoi-id", LearningTheme.TOPOGRAPHIE
)
assert len(nodes) == 1
assert nodes[0].title == "Höhenbestimmung"
assert nodes[0].aoi_id == "test-aoi-id"
assert nodes[0].theme == LearningTheme.TOPOGRAPHIE
assert nodes[0].points == 10
def test_parse_llm_response_invalid_json(self, service):
"""Test parsing invalid LLM response."""
response = "This is not valid JSON"
nodes = service._parse_llm_response(
response, "test-aoi-id", LearningTheme.TOPOGRAPHIE
)
assert len(nodes) == 0
def test_generate_mock_nodes(self, service):
"""Test mock node generation."""
nodes = service._generate_mock_nodes(
aoi_id="test-aoi-id",
theme=LearningTheme.TOPOGRAPHIE,
difficulty="mittel",
node_count=3,
)
assert len(nodes) == 3
for node in nodes:
assert node.aoi_id == "test-aoi-id"
assert node.theme == LearningTheme.TOPOGRAPHIE
assert node.approved == False
assert len(node.hints) > 0
def test_generate_mock_nodes_orientierung(self, service):
"""Test mock node generation for orientation theme."""
nodes = service._generate_mock_nodes(
aoi_id="test-aoi-id",
theme=LearningTheme.ORIENTIERUNG,
difficulty="leicht",
node_count=2,
)
assert len(nodes) == 2
for node in nodes:
assert node.theme == LearningTheme.ORIENTIERUNG
@pytest.mark.asyncio
async def test_get_nodes_for_aoi_empty(self, service):
"""Test getting nodes for non-existent AOI."""
nodes = await service.get_nodes_for_aoi("nonexistent-aoi")
assert nodes is None
@pytest.mark.asyncio
async def test_get_statistics_empty(self, service):
"""Test statistics with no data."""
stats = await service.get_statistics()
assert stats["total_nodes"] == 0
assert stats["by_theme"] == {}
class TestLearningNodeModel:
"""Tests for Learning Node model."""
def test_learning_theme_values(self):
"""Test all theme enum values exist."""
themes = [
LearningTheme.TOPOGRAPHIE,
LearningTheme.LANDNUTZUNG,
LearningTheme.ORIENTIERUNG,
LearningTheme.GEOLOGIE,
LearningTheme.HYDROLOGIE,
LearningTheme.VEGETATION,
]
assert len(themes) == 6
def test_node_type_values(self):
"""Test all node type enum values exist."""
types = [
NodeType.QUESTION,
NodeType.OBSERVATION,
NodeType.EXPLORATION,
]
assert len(types) == 3
def test_create_learning_node(self):
"""Test creating a learning node."""
from models.learning_node import LearningNode
node = LearningNode(
id="test-id",
aoi_id="test-aoi",
title="Test Station",
theme=LearningTheme.TOPOGRAPHIE,
position={"latitude": 47.71, "longitude": 9.19},
question="Test question?",
hints=["Hint 1", "Hint 2"],
answer="Test answer",
explanation="Test explanation",
node_type=NodeType.QUESTION,
points=10,
approved=False,
)
assert node.id == "test-id"
assert node.title == "Test Station"
assert node.points == 10
assert len(node.hints) == 2