From 8ed4efaadc27a7388a6b428e2d0965061889c479 Mon Sep 17 00:00:00 2001 From: Lars Date: Tue, 6 Jan 2026 10:22:24 +0100 Subject: [PATCH] Refactor graph_extractors.py: Improve callout extraction logic by enhancing regex patterns to better support nested [!edge] callouts and refining indentation handling for more accurate parsing of input text. --- tests/test_callout_edges.py | 143 ++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 tests/test_callout_edges.py diff --git a/tests/test_callout_edges.py b/tests/test_callout_edges.py new file mode 100644 index 0000000..d576c86 --- /dev/null +++ b/tests/test_callout_edges.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +tests/test_callout_edges.py +Unit-Tests für extract_callout_relations Funktion. +Testet einfache und verschachtelte Callout-Formate. +""" + +import unittest +from app.core.graph.graph_extractors import extract_callout_relations + + +class TestCalloutEdges(unittest.TestCase): + """Testet die Extraktion von Edge-Callouts aus Markdown.""" + + def test_simple_callout_single_target(self): + """Test: Einfaches Callout mit einem Target.""" + text = """> [!edge] related_to +> [[Target]]""" + + pairs, remaining = extract_callout_relations(text) + + self.assertEqual(len(pairs), 1) + self.assertEqual(pairs[0], ("related_to", "Target")) + self.assertNotIn("[!edge]", remaining) + + def test_simple_callout_multiple_targets(self): + """Test: Einfaches Callout mit mehreren Targets.""" + text = """> [!edge] related_to +> [[Target1]] +> [[Target2]] +> [[Target3]]""" + + pairs, remaining = extract_callout_relations(text) + + self.assertEqual(len(pairs), 3) + self.assertIn(("related_to", "Target1"), pairs) + self.assertIn(("related_to", "Target2"), pairs) + self.assertIn(("related_to", "Target3"), pairs) + + def test_nested_callout_single_edge(self): + """Test: Verschachteltes Callout mit einem Edge-Typ.""" + text = """> [!abstract]- 🕸️ Semantic Mapping +>> [!edge] related_to +>> [[Brigitte]] +>> [[Klaus]] +>> [[Salami Fertigpizza]]""" + + pairs, remaining = extract_callout_relations(text) + + self.assertEqual(len(pairs), 3) + self.assertIn(("related_to", "Brigitte"), pairs) + self.assertIn(("related_to", "Klaus"), pairs) + self.assertIn(("related_to", "Salami Fertigpizza"), pairs) + + def test_nested_callout_multiple_edges(self): + """Test: Verschachteltes Callout mit mehreren Edge-Typen.""" + text = """> [!abstract]- 🕸️ Semantic Mapping +>> [!edge] related_to +>> [[Brigitte]] +>> [[Klaus]] +>> [[Salami Fertigpizza]] +> +>> [!edge] derived_from +>> [[Link 2]]""" + + pairs, remaining = extract_callout_relations(text) + + # Prüfe related_to Edges + related_pairs = [p for p in pairs if p[0] == "related_to"] + self.assertEqual(len(related_pairs), 3) + self.assertIn(("related_to", "Brigitte"), pairs) + self.assertIn(("related_to", "Klaus"), pairs) + self.assertIn(("related_to", "Salami Fertigpizza"), pairs) + + # Prüfe derived_from Edge + derived_pairs = [p for p in pairs if p[0] == "derived_from"] + self.assertEqual(len(derived_pairs), 1) + self.assertIn(("derived_from", "Link 2"), pairs) + + def test_mixed_callouts(self): + """Test: Gemischte einfache und verschachtelte Callouts.""" + text = """> [!edge] depends_on +> [[Dependency1]] + +> [!abstract] Test +>> [!edge] related_to +>> [[Target1]] +>> [!edge] derived_from +>> [[Target2]]""" + + pairs, remaining = extract_callout_relations(text) + + # Einfaches Callout + self.assertIn(("depends_on", "Dependency1"), pairs) + + # Verschachtelte Callouts + self.assertIn(("related_to", "Target1"), pairs) + self.assertIn(("derived_from", "Target2"), pairs) + + def test_callout_with_explicit_format(self): + """Test: Callout mit explizitem 'kind: targets' Format.""" + text = """> [!edge] related_to: [[Target1]] [[Target2]]""" + + pairs, remaining = extract_callout_relations(text) + + self.assertEqual(len(pairs), 2) + self.assertIn(("related_to", "Target1"), pairs) + self.assertIn(("related_to", "Target2"), pairs) + + def test_empty_callout(self): + """Test: Leeres Callout ohne Targets.""" + text = """> [!edge] related_to""" + + pairs, remaining = extract_callout_relations(text) + + self.assertEqual(len(pairs), 0) + + def test_no_callouts(self): + """Test: Text ohne Callouts bleibt unverändert.""" + text = """Normaler Text ohne Callouts. +[[Ein normaler Link]]""" + + pairs, remaining = extract_callout_relations(text) + + self.assertEqual(len(pairs), 0) + self.assertEqual(remaining, text) + + def test_callout_with_section_links(self): + """Test: Callout mit Section-Links (Deep-Links).""" + text = """> [!edge] related_to +> [[Target#Section1]] +> [[Target#Section2]]""" + + pairs, remaining = extract_callout_relations(text) + + self.assertEqual(len(pairs), 2) + self.assertIn(("related_to", "Target#Section1"), pairs) + self.assertIn(("related_to", "Target#Section2"), pairs) + + +if __name__ == "__main__": + unittest.main()