""" Tests für den PDF Service. Testet: - Elternbrief-Generierung - Zeugnis-Generierung - Korrektur-Übersicht-Generierung Note: These tests require WeasyPrint which needs system libraries (libgobject). Tests are skipped if WeasyPrint cannot be loaded. """ import pytest import sys import os from datetime import datetime # Add parent directory to path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # Mark all tests in this module as requiring WeasyPrint # These tests will be automatically skipped in CI via conftest.py pytestmark = pytest.mark.requires_weasyprint class TestPDFServiceImport: """Tests für PDF Service Import und Initialisierung.""" def test_import_pdf_service(self): """Test that PDFService can be imported.""" from services.pdf_service import PDFService assert PDFService is not None def test_import_data_classes(self): """Test that data classes can be imported.""" from services.pdf_service import ( LetterData, CertificateData, CorrectionData, SchoolInfo ) assert LetterData is not None assert CertificateData is not None assert CorrectionData is not None assert SchoolInfo is not None def test_import_convenience_functions(self): """Test that convenience functions can be imported.""" from services.pdf_service import ( generate_letter_pdf, generate_certificate_pdf, generate_correction_pdf, get_pdf_service ) assert callable(generate_letter_pdf) assert callable(generate_certificate_pdf) assert callable(generate_correction_pdf) assert callable(get_pdf_service) class TestPDFServiceInitialization: """Tests für PDF Service Initialisierung.""" def test_create_pdf_service_instance(self): """Test creating a PDFService instance.""" from services.pdf_service import PDFService service = PDFService() assert service is not None assert service.templates_dir.exists() def test_get_pdf_service_singleton(self): """Test that get_pdf_service returns a singleton.""" from services.pdf_service import get_pdf_service service1 = get_pdf_service() service2 = get_pdf_service() assert service1 is service2 class TestLetterPDFGeneration: """Tests für Elternbrief-PDF-Generierung.""" def test_generate_simple_letter(self): """Test generating a simple letter PDF.""" from services.pdf_service import PDFService, LetterData service = PDFService() letter_data = LetterData( recipient_name="Familie Müller", recipient_address="Musterstraße 1\n12345 Musterstadt", student_name="Max Müller", student_class="5a", subject="Einladung zum Elternsprechtag", content="Sehr geehrte Familie Müller,\n\nhiermit laden wir Sie herzlich zum Elternsprechtag ein.", date="15.01.2025", teacher_name="Frau Schmidt", teacher_title="Klassenlehrerin", letter_type="elternabend", tone="professional" ) pdf_bytes = service.generate_letter_pdf(letter_data) assert pdf_bytes is not None assert len(pdf_bytes) > 0 # PDF magic number check assert pdf_bytes[:4] == b'%PDF' def test_generate_letter_with_school_info(self): """Test generating letter with school information.""" from services.pdf_service import PDFService, LetterData, SchoolInfo service = PDFService() school_info = SchoolInfo( name="Musterschule", address="Schulweg 10, 12345 Musterstadt", phone="0123-456789", email="info@musterschule.de", website="www.musterschule.de", principal="Dr. Hans Meier" ) letter_data = LetterData( recipient_name="Familie Schmidt", recipient_address="Hauptstraße 5\n12345 Musterstadt", student_name="Lisa Schmidt", student_class="7b", subject="Halbjahresbericht", content="Sehr geehrte Eltern,\n\nanbei erhalten Sie den Halbjahresbericht.", date="20.01.2025", teacher_name="Herr Weber", school_info=school_info, letter_type="halbjahr", tone="formal" ) pdf_bytes = service.generate_letter_pdf(letter_data) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' def test_generate_letter_with_legal_references(self): """Test generating letter with legal references.""" from services.pdf_service import PDFService, LetterData service = PDFService() letter_data = LetterData( recipient_name="Familie Braun", recipient_address="Gartenstraße 20\n12345 Musterstadt", student_name="Tim Braun", student_class="8c", subject="Fehlzeiten", content="Sehr geehrte Eltern,\n\nwir möchten Sie über die Fehlzeiten informieren.", date="25.01.2025", teacher_name="Frau Lehmann", letter_type="fehlzeiten", tone="concerned", legal_references=[ {"law": "SchulG NRW", "paragraph": "§ 42", "title": "Pflichten der Eltern"}, {"law": "SchulG NRW", "paragraph": "§ 43", "title": "Schulpflicht"} ], gfk_principles_applied=["Beobachtung", "Bedürfnis", "Bitte"] ) pdf_bytes = service.generate_letter_pdf(letter_data) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' def test_generate_letter_convenience_function(self): """Test the convenience function for letter generation.""" from services.pdf_service import generate_letter_pdf letter_dict = { "recipient_name": "Familie Test", "recipient_address": "Testweg 1\n12345 Teststadt", "student_name": "Test Kind", "student_class": "3a", "subject": "Test-Brief", "content": "Dies ist ein Testbrief.", "date": "01.02.2025", "teacher_name": "Herr Test" } pdf_bytes = generate_letter_pdf(letter_dict) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' class TestCertificatePDFGeneration: """Tests für Zeugnis-PDF-Generierung.""" def test_generate_halbjahreszeugnis(self): """Test generating a half-year certificate.""" from services.pdf_service import PDFService, CertificateData service = PDFService() cert_data = CertificateData( student_name="Anna Beispiel", student_birthdate="15.05.2012", student_class="6b", school_year="2024/2025", certificate_type="halbjahr", subjects=[ {"name": "Deutsch", "grade": "2", "points": None}, {"name": "Mathematik", "grade": "2", "points": None}, {"name": "Englisch", "grade": "1", "points": None}, {"name": "Geschichte", "grade": "2", "points": None}, {"name": "Biologie", "grade": "3", "points": None}, {"name": "Sport", "grade": "1", "points": None}, ], attendance={"days_absent": 5, "days_excused": 4, "days_unexcused": 1}, class_teacher="Frau Mustermann", principal="Dr. Hans Direktor", issue_date="31.01.2025", social_behavior="B", work_behavior="A" ) pdf_bytes = service.generate_certificate_pdf(cert_data) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' def test_generate_jahreszeugnis(self): """Test generating a full-year certificate.""" from services.pdf_service import PDFService, CertificateData service = PDFService() cert_data = CertificateData( student_name="Peter Schüler", student_birthdate="20.03.2011", student_class="7a", school_year="2024/2025", certificate_type="jahres", subjects=[ {"name": "Deutsch", "grade": "3", "points": None}, {"name": "Mathematik", "grade": "2", "points": None}, {"name": "Englisch", "grade": "2", "points": None}, ], attendance={"days_absent": 10, "days_excused": 10, "days_unexcused": 0}, remarks="Versetzung in die Klasse 8a.", class_teacher="Herr Lehrer", principal="Frau Direktorin", issue_date="15.07.2025" ) pdf_bytes = service.generate_certificate_pdf(cert_data) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' def test_generate_certificate_convenience_function(self): """Test the convenience function for certificate generation.""" from services.pdf_service import generate_certificate_pdf cert_dict = { "student_name": "Test Schüler", "student_birthdate": "01.01.2012", "student_class": "5a", "school_year": "2024/2025", "certificate_type": "halbjahr", "subjects": [ {"name": "Deutsch", "grade": "2"}, {"name": "Mathe", "grade": "3"} ], "attendance": {"days_absent": 3, "days_excused": 3, "days_unexcused": 0}, "class_teacher": "Herr Test", "principal": "Frau Test" } pdf_bytes = generate_certificate_pdf(cert_dict) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' class TestCorrectionPDFGeneration: """Tests für Korrektur-PDF-Generierung.""" def test_generate_correction_overview(self): """Test generating a correction overview PDF.""" from services.pdf_service import PDFService, CorrectionData, StudentInfo service = PDFService() student = StudentInfo( student_id="student-001", name="Maria Musterschülerin", class_name="9a" ) correction_data = CorrectionData( student=student, exam_title="Klassenarbeit Nr. 3", date="10.01.2025", subject="Mathematik", max_points=50, achieved_points=42, grade="2", percentage=84.0, grade_distribution={"1": 3, "2": 8, "3": 10, "4": 5, "5": 2, "6": 0}, class_average=2.8, corrections=[ { "question": "Lineare Gleichungen lösen", "answer": "", "points": 10, "feedback": "Alle Aufgaben korrekt gelöst." }, { "question": "Textaufgabe: Geschwindigkeit", "answer": "", "points": 12, "feedback": "Ansatz richtig, kleiner Rechenfehler am Ende." }, { "question": "Geometrie: Flächenberechnung", "answer": "", "points": 20, "feedback": "Formeln korrekt angewendet, eine Teilaufgabe fehlt." } ], teacher_notes="Insgesamt eine gute Leistung. Weiter so!" ) pdf_bytes = service.generate_correction_pdf(correction_data) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' def test_generate_correction_without_feedback(self): """Test generating correction PDF without individual feedback.""" from services.pdf_service import PDFService, CorrectionData, StudentInfo service = PDFService() student = StudentInfo( student_id="student-002", name="Tom Test", class_name="10b" ) correction_data = CorrectionData( student=student, exam_title="Vokabeltest", date="20.01.2025", subject="Englisch", max_points=20, achieved_points=18, grade="1", percentage=90.0, grade_distribution={"1": 5, "2": 10, "3": 8, "4": 2, "5": 0, "6": 0}, class_average=2.3, corrections=[ {"question": "Teil 1: Vokabeln DE-EN", "answer": "", "points": 9}, {"question": "Teil 2: Vokabeln EN-DE", "answer": "", "points": 9} ] ) pdf_bytes = service.generate_correction_pdf(correction_data) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' def test_generate_correction_convenience_function(self): """Test the convenience function for correction generation.""" from services.pdf_service import generate_correction_pdf correction_dict = { "student_id": "student-003", "student_name": "Test Student", "student_class": "8a", "exam_title": "Test Klausur", "date": "15.01.2025", "subject": "Physik", "max_points": 30, "achieved_points": 24, "grade": "2", "percentage": 80.0, "grade_distribution": {"1": 2, "2": 5, "3": 8, "4": 3, "5": 1, "6": 0}, "class_average": 2.9, "corrections": [ {"question": "Aufgabe 1", "answer": "", "points": 12, "feedback": "Gut gelöst"}, {"question": "Aufgabe 2", "answer": "", "points": 12, "feedback": "Korrekt"} ], "teacher_notes": "Insgesamt gute Arbeit." } pdf_bytes = generate_correction_pdf(correction_dict) assert pdf_bytes is not None assert len(pdf_bytes) > 0 assert pdf_bytes[:4] == b'%PDF' class TestPDFServiceHelpers: """Tests für Hilfsfunktionen des PDF Service.""" def test_date_format_filter(self): """Test the date format filter.""" from services.pdf_service import PDFService service = PDFService() # ISO date format result = service._date_format("2025-01-15") assert result == "15.01.2025" # Empty value result = service._date_format("") assert result == "" # Already formatted result = service._date_format("15.01.2025") assert result == "15.01.2025" def test_grade_color_filter(self): """Test the grade color filter.""" from services.pdf_service import PDFService service = PDFService() # German grades assert service._grade_color("1") == "#27ae60" assert service._grade_color("2") == "#2ecc71" assert service._grade_color("3") == "#f1c40f" assert service._grade_color("4") == "#e67e22" assert service._grade_color("5") == "#e74c3c" assert service._grade_color("6") == "#c0392b" # Behavior grades assert service._grade_color("A") == "#27ae60" assert service._grade_color("B") == "#2ecc71" # Unknown grade assert service._grade_color("X") == "#333333" class TestPDFTemplates: """Tests für PDF Templates.""" def test_templates_directory_created(self): """Test that templates directory is created.""" from services.pdf_service import PDFService from pathlib import Path service = PDFService() assert service.templates_dir.exists() assert service.templates_dir.is_dir() def test_inline_templates_work(self): """Test that inline templates work as fallback.""" from services.pdf_service import PDFService service = PDFService() # Test letter template template_html = service._get_letter_template_html() assert "{{ data.subject }}" in template_html assert "{{ data.content" in template_html # Test certificate template template_html = service._get_certificate_template_html() assert "{{ data.student_name }}" in template_html # data.subjects is used in a for loop, not direct output assert "data.subjects" in template_html # Test correction template template_html = service._get_correction_template_html() assert "{{ data.exam_title }}" in template_html # data.corrections is used in a for loop, not direct output assert "data.corrections" in template_html # Run tests if executed directly if __name__ == "__main__": pytest.main([__file__, "-v"])