""" 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"])