""" Tests für Worksheets API. Testet alle Content-Generatoren: - Multiple Choice - Cloze (Lückentext) - Mindmap - Quiz """ import pytest from fastapi.testclient import TestClient # Importiere main app import sys import os sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from main import app client = TestClient(app) # Sample text für Tests (mind. 50 Zeichen erforderlich) SAMPLE_TEXT = """ Die Photosynthese ist ein biologischer Prozess, bei dem Pflanzen, Algen und einige Bakterien Lichtenergie in chemische Energie umwandeln. Dieser Vorgang findet hauptsächlich in den Chloroplasten der Pflanzenzellen statt. Dabei werden Kohlendioxid und Wasser unter Verwendung von Sonnenlicht in Glucose und Sauerstoff umgewandelt. Die Photosynthese ist fundamental für das Leben auf der Erde, da sie Sauerstoff produziert und die Basis der Nahrungskette bildet. Pflanzen nutzen die produzierte Glucose als Energiequelle für ihr Wachstum. """ SHORT_TEXT = "Zu kurz" class TestMultipleChoiceGeneration: """Tests für Multiple Choice Generierung.""" def test_generate_mc_success(self): """Testet erfolgreiche MC-Generierung.""" response = client.post( "/api/worksheets/generate/multiple-choice", json={ "source_text": SAMPLE_TEXT, "num_questions": 3, "difficulty": "medium", "topic": "Photosynthese", "subject": "Biologie" } ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["content"] is not None assert data["content"]["content_type"] == "multiple_choice" assert "questions" in data["content"]["data"] def test_generate_mc_with_h5p(self): """Testet H5P-Export für MC.""" response = client.post( "/api/worksheets/generate/multiple-choice", json={ "source_text": SAMPLE_TEXT, "num_questions": 2, "difficulty": "easy" } ) assert response.status_code == 200 data = response.json() assert data["content"]["h5p_format"] is not None assert data["content"]["h5p_format"]["library"] == "H5P.MultiChoice" def test_generate_mc_text_too_short(self): """Testet Fehler bei zu kurzem Text.""" response = client.post( "/api/worksheets/generate/multiple-choice", json={ "source_text": SHORT_TEXT, "num_questions": 3 } ) # Pydantic Validation sollte fehlschlagen assert response.status_code == 422 def test_generate_mc_difficulty_levels(self): """Testet verschiedene Schwierigkeitsgrade.""" for difficulty in ["easy", "medium", "hard"]: response = client.post( "/api/worksheets/generate/multiple-choice", json={ "source_text": SAMPLE_TEXT, "num_questions": 2, "difficulty": difficulty } ) assert response.status_code == 200 data = response.json() assert data["content"]["difficulty"] == difficulty class TestClozeGeneration: """Tests für Lückentext-Generierung.""" def test_generate_cloze_fill_in(self): """Testet Fill-in Lückentext.""" response = client.post( "/api/worksheets/generate/cloze", json={ "source_text": SAMPLE_TEXT, "num_gaps": 3, "cloze_type": "fill_in", "topic": "Photosynthese" } ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["content"]["content_type"] == "cloze" assert "gaps" in data["content"]["data"] assert "text_with_gaps" in data["content"]["data"] def test_generate_cloze_drag_drop(self): """Testet Drag-Drop Lückentext.""" response = client.post( "/api/worksheets/generate/cloze", json={ "source_text": SAMPLE_TEXT, "num_gaps": 4, "cloze_type": "drag_drop" } ) assert response.status_code == 200 data = response.json() assert data["content"]["data"]["cloze_type"] == "drag_drop" def test_generate_cloze_dropdown(self): """Testet Dropdown Lückentext.""" response = client.post( "/api/worksheets/generate/cloze", json={ "source_text": SAMPLE_TEXT, "num_gaps": 3, "cloze_type": "dropdown" } ) assert response.status_code == 200 data = response.json() assert data["content"]["data"]["cloze_type"] == "dropdown" def test_generate_cloze_h5p_format(self): """Testet H5P-Export für Cloze.""" response = client.post( "/api/worksheets/generate/cloze", json={ "source_text": SAMPLE_TEXT, "num_gaps": 3 } ) assert response.status_code == 200 data = response.json() assert data["content"]["h5p_format"]["library"] == "H5P.Blanks" class TestMindmapGeneration: """Tests für Mindmap-Generierung.""" def test_generate_mindmap_success(self): """Testet erfolgreiche Mindmap-Generierung.""" response = client.post( "/api/worksheets/generate/mindmap", json={ "source_text": SAMPLE_TEXT, "topic": "Photosynthese", "max_depth": 3 } ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["content"]["content_type"] == "mindmap" assert "mindmap" in data["content"]["data"] assert "mermaid" in data["content"]["data"] assert "json_tree" in data["content"]["data"] def test_generate_mindmap_no_h5p(self): """Testet dass Mindmaps kein H5P-Format haben.""" response = client.post( "/api/worksheets/generate/mindmap", json={ "source_text": SAMPLE_TEXT, "max_depth": 2 } ) assert response.status_code == 200 data = response.json() assert data["content"]["h5p_format"] is None def test_generate_mindmap_structure(self): """Testet Mindmap-Struktur.""" response = client.post( "/api/worksheets/generate/mindmap", json={ "source_text": SAMPLE_TEXT, "max_depth": 3 } ) data = response.json() mindmap = data["content"]["data"]["mindmap"] assert "root" in mindmap assert "title" in mindmap assert "total_nodes" in mindmap assert mindmap["root"]["level"] == 0 class TestQuizGeneration: """Tests für Quiz-Generierung.""" def test_generate_quiz_true_false(self): """Testet True/False Quiz.""" response = client.post( "/api/worksheets/generate/quiz", json={ "source_text": SAMPLE_TEXT, "quiz_types": ["true_false"], "num_items": 3 } ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert "questions" in data["content"]["data"] # All questions should be of type true_false questions = data["content"]["data"]["questions"] assert len(questions) > 0 assert all(q["type"] == "true_false" for q in questions) def test_generate_quiz_matching(self): """Testet Matching Quiz mit definitionsreichem Text.""" # Text with clear definition patterns for matching extraction definition_text = """ Photosynthese ist der Prozess der Umwandlung von Lichtenergie in chemische Energie. Chloroplasten bezeichnet die Zellorganellen, in denen die Photosynthese stattfindet. Glucose bedeutet Traubenzucker, ein einfacher Zucker. ATP: Adenosintriphosphat, der universelle Energietraeger der Zellen. Chlorophyll ist der gruene Farbstoff, der Licht absorbiert. """ response = client.post( "/api/worksheets/generate/quiz", json={ "source_text": definition_text, "quiz_types": ["matching"], "num_items": 3 } ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert "questions" in data["content"]["data"] # All questions should be of type matching questions = data["content"]["data"]["questions"] assert len(questions) > 0 assert all(q["type"] == "matching" for q in questions) def test_generate_quiz_combined(self): """Testet kombiniertes Quiz mit mehreren Typen.""" response = client.post( "/api/worksheets/generate/quiz", json={ "source_text": SAMPLE_TEXT, "quiz_types": ["true_false", "matching", "sorting"], "num_items": 2, "difficulty": "medium" } ) assert response.status_code == 200 data = response.json() quiz_data = data["content"]["data"] assert "questions" in quiz_data assert "quiz_types" in quiz_data # Should have questions from multiple types question_types = set(q["type"] for q in quiz_data["questions"]) assert len(question_types) >= 1 # At least one type should have generated questions class TestBatchGeneration: """Tests für Batch-Generierung.""" def test_batch_generate_multiple_types(self): """Testet Generierung mehrerer Content-Typen.""" response = client.post( "/api/worksheets/generate/batch", json={ "source_text": SAMPLE_TEXT, "content_types": ["multiple_choice", "cloze"], "topic": "Photosynthese", "difficulty": "medium" } ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert len(data["contents"]) == 2 content_types = [c["content_type"] for c in data["contents"]] assert "multiple_choice" in content_types assert "cloze" in content_types def test_batch_generate_all_types(self): """Testet Generierung aller Content-Typen.""" response = client.post( "/api/worksheets/generate/batch", json={ "source_text": SAMPLE_TEXT, "content_types": ["multiple_choice", "cloze", "mindmap", "quiz"], "topic": "Test" } ) assert response.status_code == 200 data = response.json() assert len(data["contents"]) == 4 def test_batch_generate_partial_failure(self): """Testet Batch mit unbekanntem Typ.""" response = client.post( "/api/worksheets/generate/batch", json={ "source_text": SAMPLE_TEXT, "content_types": ["multiple_choice", "unknown_type"], "topic": "Test" } ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert len(data["contents"]) == 1 assert len(data["errors"]) == 1 assert "unknown_type" in data["errors"][0] class TestContentManagement: """Tests für Content-Verwaltung.""" def test_get_content(self): """Testet Abrufen von gespeichertem Content.""" # Erst generieren gen_response = client.post( "/api/worksheets/generate/multiple-choice", json={ "source_text": SAMPLE_TEXT, "num_questions": 2 } ) content_id = gen_response.json()["content"]["id"] # Dann abrufen get_response = client.get(f"/api/worksheets/content/{content_id}") assert get_response.status_code == 200 data = get_response.json() assert data["content"]["id"] == content_id def test_get_content_not_found(self): """Testet Fehler bei nicht vorhandenem Content.""" response = client.get("/api/worksheets/content/nonexistent-id") assert response.status_code == 404 def test_get_content_h5p(self): """Testet H5P-Format Abruf.""" # Erst generieren gen_response = client.post( "/api/worksheets/generate/multiple-choice", json={ "source_text": SAMPLE_TEXT, "num_questions": 2 } ) content_id = gen_response.json()["content"]["id"] # H5P abrufen h5p_response = client.get(f"/api/worksheets/content/{content_id}/h5p") assert h5p_response.status_code == 200 data = h5p_response.json() assert "library" in data assert "params" in data def test_delete_content(self): """Testet Löschen von Content.""" # Erst generieren gen_response = client.post( "/api/worksheets/generate/cloze", json={ "source_text": SAMPLE_TEXT, "num_gaps": 3 } ) content_id = gen_response.json()["content"]["id"] # Dann löschen del_response = client.delete(f"/api/worksheets/content/{content_id}") assert del_response.status_code == 200 assert del_response.json()["status"] == "deleted" # Prüfen dass gelöscht get_response = client.get(f"/api/worksheets/content/{content_id}") assert get_response.status_code == 404 class TestMetaEndpoints: """Tests für Meta-Endpoints.""" def test_list_content_types(self): """Testet Auflistung der Content-Typen.""" response = client.get("/api/worksheets/types") assert response.status_code == 200 data = response.json() assert "content_types" in data assert len(data["content_types"]) == 4 type_names = [t["type"] for t in data["content_types"]] assert "multiple_choice" in type_names assert "cloze" in type_names assert "mindmap" in type_names assert "quiz" in type_names def test_get_generation_history(self): """Testet Generierungs-Historie.""" # Erst etwas generieren client.post( "/api/worksheets/generate/mindmap", json={ "source_text": SAMPLE_TEXT, "topic": "History Test" } ) response = client.get("/api/worksheets/history?limit=5") assert response.status_code == 200 data = response.json() assert "total" in data assert "contents" in data assert data["total"] >= 1 class TestGeneratorIntegration: """Tests für Generator-Integration.""" def test_mc_generator_output_format(self): """Testet MC-Generator Output-Format.""" response = client.post( "/api/worksheets/generate/multiple-choice", json={ "source_text": SAMPLE_TEXT, "num_questions": 2 } ) data = response.json() questions = data["content"]["data"]["questions"] for q in questions: assert "question" in q assert "options" in q assert len(q["options"]) == 4 assert "difficulty" in q # Genau eine richtige Antwort correct_count = sum(1 for opt in q["options"] if opt["is_correct"]) assert correct_count == 1 def test_cloze_generator_gap_format(self): """Testet Cloze-Generator Gap-Format.""" response = client.post( "/api/worksheets/generate/cloze", json={ "source_text": SAMPLE_TEXT, "num_gaps": 3 } ) data = response.json() gaps = data["content"]["data"]["gaps"] for gap in gaps: assert "position" in gap assert "answer" in gap assert "alternatives" in gap assert "distractors" in gap def test_mindmap_generator_node_format(self): """Testet Mindmap-Generator Node-Format.""" response = client.post( "/api/worksheets/generate/mindmap", json={ "source_text": SAMPLE_TEXT, "max_depth": 3 } ) data = response.json() root = data["content"]["data"]["mindmap"]["root"] assert "id" in root assert "label" in root assert "level" in root assert "children" in root assert "color" in root