mitai-jinkendo/tests/backend/test_phase1_result_container_parser.py

235 lines
6.1 KiB
Python
Raw Normal View History

"""
Unit Tests für result_container_parser.py (Phase 1)
Run with: PYTHONPATH=./backend pytest tests/backend/test_phase1_result_container_parser.py -v
"""
import pytest
from result_container_parser import (
parse_result_container,
extract_section,
parse_decision_questions,
validate_decision_signal,
parse_result_container_robust
)
def test_extract_section_basic():
"""Test: Einfache Sektion extrahieren"""
text = """
## Analyse
Das ist der Analysekern.
Mehrere Zeilen.
## Entscheidungsfragen
- Relevanz: ja
"""
result = extract_section(text, "Analyse")
assert result == "Das ist der Analysekern.\nMehrere Zeilen."
def test_extract_section_not_found():
"""Test: Nicht vorhandene Sektion"""
text = "## Analyse\nInhalt"
result = extract_section(text, "Begründung")
assert result is None
def test_extract_section_empty():
"""Test: Leere Sektion (nur Whitespace am Ende)"""
text = "## Analyse\n\n"
result = extract_section(text, "Analyse")
assert result is None
def test_parse_decision_questions_basic():
"""Test: Standard-Format parsen"""
section = """
- Relevanz: ja
- Priorität: hoch
- Selektion: nein
"""
result = parse_decision_questions(section)
assert result == {
"relevanz": "ja",
"priorität": "hoch",
"selektion": "nein"
}
def test_parse_decision_questions_bold():
"""Test: Format mit **bold** Markup"""
section = """
- **Relevanz**: ja
- **Priorität**: hoch
"""
result = parse_decision_questions(section)
assert result == {
"relevanz": "ja",
"priorität": "hoch"
}
def test_parse_decision_questions_without_dash():
"""Test: Format ohne führendes Minus"""
section = """
Relevanz: ja
Priorität: hoch
"""
result = parse_decision_questions(section)
assert result == {
"relevanz": "ja",
"priorität": "hoch"
}
def test_parse_decision_questions_brackets():
"""Test: Format mit [Klammern]"""
section = """
- Relevanz: [ja]
- Priorität: [hoch]
"""
result = parse_decision_questions(section)
assert result == {
"relevanz": "ja",
"priorität": "hoch"
}
def test_validate_decision_signal_exact_match():
"""Test: Exakte Übereinstimmung"""
value, status = validate_decision_signal("ja", ["ja", "nein", "unklar"])
assert value == "ja"
assert status == "valid"
def test_validate_decision_signal_normalized():
"""Test: Case-insensitive Normalisierung"""
value, status = validate_decision_signal("JA", ["ja", "nein", "unklar"])
assert value == "ja"
assert status == "normalized"
def test_validate_decision_signal_invalid():
"""Test: Ungültige Antwort"""
value, status = validate_decision_signal("vielleicht", ["ja", "nein", "unklar"])
assert value == "vielleicht"
assert status == "invalid"
def test_parse_result_container_complete():
"""Test: Vollständiger Container mit allen Sektionen"""
llm_output = """
## Analyse
Der Nutzer zeigt eine positive Gewichtsentwicklung.
Kaloriendefizit wird eingehalten.
## Entscheidungsfragen
- Relevanz: ja
- Priorität: hoch
## Begründung
Die Gewichtsabnahme ist im Zielbereich von 0.5-1% pro Woche.
"""
result = parse_result_container(llm_output)
assert result["parsing_status"] == "complete"
assert "Gewichtsentwicklung" in result["analysis_core"]
assert result["decision_signals"]["relevanz"] == "ja"
assert result["decision_signals"]["priorität"] == "hoch"
assert "Zielbereich" in result["reasoning_anchors"]
def test_parse_result_container_partial():
"""Test: Container ohne Begründung (partial)"""
llm_output = """
## Analyse
Analyse-Inhalt
## Entscheidungsfragen
- Relevanz: ja
"""
result = parse_result_container(llm_output)
assert result["parsing_status"] == "complete"
assert result["analysis_core"] == "Analyse-Inhalt"
assert result["decision_signals"]["relevanz"] == "ja"
assert result["reasoning_anchors"] is None
def test_parse_result_container_no_structure():
"""Test: Unstrukturierte Antwort (Fallback)"""
llm_output = "Einfache Textantwort ohne Strukturierung."
result = parse_result_container(llm_output)
assert result["parsing_status"] == "fallback"
assert result["analysis_core"] == "Einfache Textantwort ohne Strukturierung."
assert result["decision_signals"] == {}
assert result["reasoning_anchors"] is None
def test_parse_result_container_only_questions():
"""Test: Nur Entscheidungsfragen, keine Analyse (partial)"""
llm_output = """
## Entscheidungsfragen
- Relevanz: nein
- Priorität: niedrig
"""
result = parse_result_container(llm_output)
assert result["parsing_status"] == "partial"
assert result["analysis_core"] == ""
assert result["decision_signals"]["relevanz"] == "nein"
def test_parse_result_container_robust_with_warnings():
"""Test: Robuste Variante mit erwarteten Fragen"""
llm_output = """
## Analyse
Inhalt
## Entscheidungsfragen
- Relevanz: ja
"""
expected_questions = ["relevanz", "prioritaet", "selektion"]
result = parse_result_container_robust(llm_output, expected_questions)
assert "warnings" in result
assert any("Fehlende Entscheidungsfragen" in w for w in result["warnings"])
assert any("prioritaet" in w for w in result["warnings"])
def test_parse_result_container_case_insensitive():
"""Test: Case-insensitive Sektion-Matching"""
llm_output = """
## ANALYSE
Großgeschrieben
## entscheidungsfragen
- Relevanz: ja
"""
result = parse_result_container(llm_output)
assert result["parsing_status"] == "complete"
assert result["analysis_core"] == "Großgeschrieben"
assert result["decision_signals"]["relevanz"] == "ja"
def test_parse_decision_questions_mixed_formats():
"""Test: Gemischte Formate in einer Sektion"""
section = """
- **Relevanz**: ja
Priorität: hoch
- Selektion: [nein]
"""
result = parse_decision_questions(section)
assert result["relevanz"] == "ja"
assert result["priorität"] == "hoch"
assert result["selektion"] == "nein"
if __name__ == "__main__":
pytest.main([__file__, "-v"])