diff --git a/abschnitte/tests.py b/abschnitte/tests.py index 7ce503c..8d8d8b9 100644 --- a/abschnitte/tests.py +++ b/abschnitte/tests.py @@ -1,3 +1,820 @@ -from django.test import TestCase +from django.test import TestCase, TransactionTestCase +from django.core.management import call_command +from django.conf import settings +from django.core.files.storage import default_storage +from unittest.mock import patch, Mock, MagicMock +from io import StringIO +import os +import hashlib +import tempfile +import shutil -# Create your tests here. +from .models import AbschnittTyp, Textabschnitt +from .utils import render_textabschnitte, md_table_to_html +from diagramm_proxy.diagram_cache import ( + get_cached_diagram, compute_hash, get_cache_path, clear_cache +) + + +class AbschnittTypModelTest(TestCase): + """Test cases for AbschnittTyp model""" + + def setUp(self): + """Set up test data""" + self.abschnitttyp = AbschnittTyp.objects.create( + abschnitttyp="text" + ) + + def test_abschnitttyp_creation(self): + """Test that AbschnittTyp is created correctly""" + self.assertEqual(self.abschnitttyp.abschnitttyp, "text") + + def test_abschnitttyp_str(self): + """Test string representation of AbschnittTyp""" + self.assertEqual(str(self.abschnitttyp), "text") + + def test_abschnitttyp_verbose_name_plural(self): + """Test verbose name plural""" + self.assertEqual( + AbschnittTyp._meta.verbose_name_plural, + "Abschnitttypen" + ) + + def test_abschnitttyp_primary_key(self): + """Test that abschnitttyp field is the primary key""" + pk_field = AbschnittTyp._meta.pk + self.assertEqual(pk_field.name, 'abschnitttyp') + + def test_create_multiple_abschnitttypen(self): + """Test creating multiple AbschnittTyp objects""" + types = ['liste ungeordnet', 'liste geordnet', 'tabelle', 'diagramm', 'code'] + for typ in types: + AbschnittTyp.objects.create(abschnitttyp=typ) + + self.assertEqual(AbschnittTyp.objects.count(), 6) # Including setUp type + + +class TextabschnittModelTest(TestCase): + """Test cases for Textabschnitt abstract model using VorgabeLangtext""" + + def setUp(self): + """Set up test data""" + from dokumente.models import Dokumententyp, Dokument, Vorgabe, VorgabeLangtext, Thema + from datetime import date + + self.typ_text = AbschnittTyp.objects.create(abschnitttyp="text") + self.typ_code = AbschnittTyp.objects.create(abschnitttyp="code") + + # Create required dokumente objects + self.dokumententyp = Dokumententyp.objects.create( + name="Test Type", verantwortliche_ve="TEST" + ) + self.dokument = Dokument.objects.create( + nummer="TEST-001", + name="Test Doc", + dokumententyp=self.dokumententyp, + aktiv=True + ) + self.thema = Thema.objects.create(name="Test Thema") + self.vorgabe = Vorgabe.objects.create( + dokument=self.dokument, + nummer=1, + order=1, + thema=self.thema, + titel="Test Vorgabe", + gueltigkeit_von=date.today() + ) + + def test_textabschnitt_creation(self): + """Test that Textabschnitt can be instantiated via concrete model""" + from dokumente.models import VorgabeLangtext + + abschnitt = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="Test content", + order=1 + ) + self.assertEqual(abschnitt.abschnitttyp, self.typ_text) + self.assertEqual(abschnitt.inhalt, "Test content") + self.assertEqual(abschnitt.order, 1) + + def test_textabschnitt_default_order(self): + """Test that order defaults to 0""" + from dokumente.models import VorgabeLangtext + + abschnitt = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="Test" + ) + self.assertEqual(abschnitt.order, 0) + + def test_textabschnitt_blank_fields(self): + """Test that abschnitttyp and inhalt can be blank/null""" + from dokumente.models import VorgabeLangtext + + abschnitt = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe + ) + self.assertIsNone(abschnitt.abschnitttyp) + self.assertIsNone(abschnitt.inhalt) + + def test_textabschnitt_ordering(self): + """Test that Textabschnitte can be ordered""" + from dokumente.models import VorgabeLangtext + + abschnitt1 = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="First", + order=2 + ) + abschnitt2 = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="Second", + order=1 + ) + abschnitt3 = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="Third", + order=3 + ) + + ordered = VorgabeLangtext.objects.filter(abschnitt=self.vorgabe).order_by('order') + self.assertEqual(list(ordered), [abschnitt2, abschnitt1, abschnitt3]) + + def test_textabschnitt_foreign_key_protection(self): + """Test that AbschnittTyp is protected from deletion""" + from dokumente.models import VorgabeLangtext + from django.db.models import ProtectedError + + abschnitt = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="Test" + ) + + # Try to delete the AbschnittTyp + with self.assertRaises(ProtectedError): + self.typ_text.delete() + + +class RenderTextabschnitteTest(TestCase): + """Test cases for render_textabschnitte function""" + + def setUp(self): + """Set up test data""" + from dokumente.models import Dokumententyp, Dokument, Vorgabe, VorgabeLangtext, Thema + from datetime import date + + self.typ_text = AbschnittTyp.objects.create(abschnitttyp="text") + self.typ_unordered = AbschnittTyp.objects.create(abschnitttyp="liste ungeordnet") + self.typ_ordered = AbschnittTyp.objects.create(abschnitttyp="liste geordnet") + self.typ_table = AbschnittTyp.objects.create(abschnitttyp="tabelle") + self.typ_code = AbschnittTyp.objects.create(abschnitttyp="code") + self.typ_diagram = AbschnittTyp.objects.create(abschnitttyp="diagramm") + + # Create required dokumente objects + self.dokumententyp = Dokumententyp.objects.create( + name="Test Type", verantwortliche_ve="TEST" + ) + self.dokument = Dokument.objects.create( + nummer="TEST-001", + name="Test Doc", + dokumententyp=self.dokumententyp, + aktiv=True + ) + self.thema = Thema.objects.create(name="Test Thema") + self.vorgabe = Vorgabe.objects.create( + dokument=self.dokument, + nummer=1, + order=1, + thema=self.thema, + titel="Test Vorgabe", + gueltigkeit_von=date.today() + ) + + def test_render_empty_queryset(self): + """Test rendering an empty queryset""" + from dokumente.models import VorgabeLangtext + + result = render_textabschnitte(VorgabeLangtext.objects.none()) + self.assertEqual(result, []) + + def test_render_text_markdown(self): + """Test rendering plain text with markdown""" + from dokumente.models import VorgabeLangtext + + abschnitt = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="# Heading\n\nThis is **bold** text.", + order=1 + ) + + result = render_textabschnitte(VorgabeLangtext.objects.filter(abschnitt=self.vorgabe)) + self.assertEqual(len(result), 1) + typ, html = result[0] + self.assertEqual(typ, "text") + self.assertIn("

Heading

", html) + self.assertIn("bold", html) + + def test_render_text_with_footnotes(self): + """Test rendering text with footnotes""" + from dokumente.models import VorgabeLangtext + + abschnitt = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_text, + inhalt="This is text[^1].\n\n[^1]: This is a footnote.", + order=1 + ) + + result = render_textabschnitte(VorgabeLangtext.objects.filter(abschnitt=self.vorgabe)) + typ, html = result[0] + self.assertIn("footnote", html.lower()) + + def test_render_unordered_list(self): + """Test rendering unordered list""" + from dokumente.models import VorgabeLangtext + + abschnitt = VorgabeLangtext.objects.create( + abschnitt=self.vorgabe, + abschnitttyp=self.typ_unordered, + inhalt="Item 1\nItem 2\nItem 3", + order=1 + ) + + result = render_textabschnitte(VorgabeLangtext.objects.filter(abschnitt=self.vorgabe)) + typ, html = result[0] + self.assertEqual(typ, "liste ungeordnet") + self.assertIn("