#!/usr/bin/env python3 """ Test-Skript für die erweiterte XML-Hash-Duplikatserkennung. Testet die neuen Funktionalitäten in MainWindow. """ import hashlib import tempfile import shutil from pathlib import Path import sys import os # Füge src-Verzeichnis zum Python-Pfad hinzu sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) from conf import XmlFile, XslFile, TreeNode, ProjectData def create_test_xml_file(content: str, filename: str) -> Path: """Erstellt eine temporäre XML-Testdatei.""" temp_dir = Path(tempfile.mkdtemp()) xml_file = temp_dir / filename with open(xml_file, 'w', encoding='utf-8') as f: f.write(content) return xml_file def calculate_test_hash(file_path: Path) -> str: """Berechnet den blake2b-Hash für eine Testdatei.""" with open(file_path, 'rb') as f: file_content = f.read() hash_obj = hashlib.blake2b(file_content) return f"blake2b:{hash_obj.hexdigest()}" def test_hash_calculation(): """Testet die Hash-Berechnung.""" print("=== Test: Hash-Berechnung ===") # Erstelle Testdatei test_content = """ Hash-Berechnung Test """ xml_file = create_test_xml_file(test_content, "test_hash.xml") try: # Berechne Hash calculated_hash = calculate_test_hash(xml_file) print(f"Berechneter Hash: {calculated_hash}") # Verifikation assert calculated_hash.startswith("blake2b:"), "Hash-Präfix fehlt!" # blake2b erzeugt 128-stellige Hex-Strings + 8 Zeichen für "blake2b:" = 136 Zeichen assert len(calculated_hash) == 136, f"Hash-Länge falsch: {len(calculated_hash)} (erwartet: 136)" print("[OK] Hash-Berechnung funktioniert korrekt") return calculated_hash finally: # Aufräumen shutil.rmtree(xml_file.parent) def test_xml_file_model_with_hash(): """Testet das erweiterte XmlFile-Modell mit Hash.""" print("\n=== Test: XmlFile-Modell mit Hash ===") # Test 1: XmlFile ohne Hash xml_file1 = XmlFile(xml=Path("test1.xml")) print(f"XmlFile ohne Hash: {xml_file1}") assert xml_file1.hashsum is None, "Initiale hashsum sollte None sein" # Test 2: XmlFile mit Hash test_hash = "blake2b:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" xml_file2 = XmlFile(xml=Path("test2.xml"), hashsum=test_hash) print(f"XmlFile mit Hash: {xml_file2}") assert xml_file2.hashsum == test_hash, "Hash stimmt nicht überein" print("[OK] XmlFile-Modell mit Hash funktioniert korrekt") def test_duplicate_detection_logic(): """Testet die Duplikatserkennung-Logik.""" print("\n=== Test: Duplikatserkennung-Logik ===") # Erstelle Test-Projektstruktur hash1 = "blake2b:1111111111111111111111111111111111111111111111111111111111111111" hash2 = "blake2b:2222222222222222222222222222222222222222222222222222222222222222" # XML-Dateien mit verschiedenen Hashes xml1 = XmlFile(xml=Path("xml/file1.xml"), hashsum=hash1) xml2 = XmlFile(xml=Path("xml/file2.xml"), hashsum=hash2) xml3 = XmlFile(xml=Path("xml/file3.xml"), hashsum=hash1) # Duplikat von xml1 # XSL-Dateien xsl1 = XslFile(id=(1,), bez="XSL 1", xsl_file=Path("xsl1.xsl"), xmls=[xml1, xml2]) xsl2 = XslFile(id=(2,), bez="XSL 2", xsl_file=Path("xsl2.xsl"), xmls=[xml3]) # TreeNode tree_node = TreeNode(id=(1,), bez="Test Node", children=[xsl1, xsl2]) # Projekt project = ProjectData(nodes=[tree_node]) # Sammle alle XML-Dateien all_xml_files = [] def collect_xml_files(nodes): for node in nodes: if isinstance(node, XslFile) and node.xmls: for xml_file in node.xmls: if not any(existing.xml == xml_file.xml for existing in all_xml_files): all_xml_files.append(xml_file) elif isinstance(node, TreeNode) and node.children: collect_xml_files(node.children) collect_xml_files(project.nodes) print(f"Gesammelte XML-Dateien: {len(all_xml_files)}") for xml in all_xml_files: print(f" - {xml.xml}: {xml.hashsum}") # Test Hash-Suche def find_xml_by_hash(target_hash): for xml_file in all_xml_files: if xml_file.hashsum == target_hash: return xml_file return None # Test 1: Existierenden Hash finden found_xml = find_xml_by_hash(hash1) assert found_xml is not None, "Hash1 sollte gefunden werden" assert found_xml.xml == Path("xml/file1.xml"), "Falsches XML-File gefunden" print(f"Hash-Suche erfolgreich: {found_xml.xml}") # Test 2: Nicht existierenden Hash suchen non_existent_hash = "blake2b:9999999999999999999999999999999999999999999999999999999999999999" not_found = find_xml_by_hash(non_existent_hash) assert not_found is None, "Nicht existierender Hash sollte None zurückgeben" print("Nicht existierender Hash korrekt behandelt") print("[OK] Duplikatserkennung-Logik funktioniert korrekt") def test_alternative_filename_generation(): """Testet die Generierung alternativer Dateinamen.""" print("\n=== Test: Alternative Dateinamen-Generierung ===") # Simuliere existierende Dateien existing_files = { "test.xml", "test_1.xml", "test_2.xml", "document.xml" } def generate_alternative_name(original_name: str) -> str: """Simuliert die Generierung alternativer Namen.""" base_name = Path(original_name).stem extension = Path(original_name).suffix counter = 1 while True: new_name = f"{base_name}_{counter}{extension}" if new_name not in existing_files: return new_name counter += 1 if counter > 100: # Sicherheitsgrenze break return f"{base_name}_fallback{extension}" # Test 1: Datei existiert bereits alt_name1 = generate_alternative_name("test.xml") expected1 = "test_3.xml" # test.xml, test_1.xml, test_2.xml existieren bereits assert alt_name1 == expected1, f"Erwarteter Name: {expected1}, erhalten: {alt_name1}" print(f"Alternative für 'test.xml': {alt_name1}") # Test 2: Datei existiert nicht alt_name2 = generate_alternative_name("new_file.xml") expected2 = "new_file_1.xml" assert alt_name2 == expected2, f"Erwarteter Name: {expected2}, erhalten: {alt_name2}" print(f"Alternative für 'new_file.xml': {alt_name2}") # Test 3: Datei ohne Konflikte alt_name3 = generate_alternative_name("unique.xml") expected3 = "unique_1.xml" assert alt_name3 == expected3, f"Erwarteter Name: {expected3}, erhalten: {alt_name3}" print(f"Alternative für 'unique.xml': {alt_name3}") print("[OK] Alternative Dateinamen-Generierung funktioniert korrekt") def test_integration_workflow(): """Testet den kompletten Workflow der Integration.""" print("\n=== Test: Integration Workflow ===") # Simuliere den kompletten Workflow # 1. Neue XML-Datei new_xml_content = """ Integration Test Test-Inhalt für Integration """ new_xml_file = create_test_xml_file(new_xml_content, "integration_test.xml") new_hash = calculate_test_hash(new_xml_file) try: # 2. Bestehende Projekt-XML-Dateien simulieren existing_xml1 = XmlFile(xml=Path("xml/existing1.xml"), hashsum="blake2b:aaaa") existing_xml2 = XmlFile(xml=Path("xml/existing2.xml"), hashsum="blake2b:bbbb") existing_xml3 = XmlFile(xml=Path("xml/existing3.xml"), hashsum=new_hash) # Duplikat! existing_xmls = [existing_xml1, existing_xml2, existing_xml3] # 3. Hash-Vergleich duplicate_found = None for existing_xml in existing_xmls: if existing_xml.hashsum == new_hash: duplicate_found = existing_xml break # 4. Verifikation assert duplicate_found is not None, "Duplikat sollte gefunden werden" assert duplicate_found.xml == Path("xml/existing3.xml"), "Falsches Duplikat gefunden" print("Workflow-Test erfolgreich:") print(f" - Neue Datei: {new_xml_file.name}") print(f" - Berechneter Hash: {new_hash}") print(f" - Duplikat gefunden: {duplicate_found.xml}") print(" - Automatische Zuordnung würde erfolgen") print("[OK] Integration Workflow funktioniert korrekt") finally: # Aufräumen shutil.rmtree(new_xml_file.parent) if __name__ == "__main__": print("Starte Tests für XML-Hash-Duplikatserkennung...\n") try: test_hash_calculation() test_xml_file_model_with_hash() test_duplicate_detection_logic() test_alternative_filename_generation() test_integration_workflow() print("\n" + "="*60) print("[SUCCESS] Alle Tests erfolgreich abgeschlossen!") print("\nDie erweiterte XML-Hash-Duplikatserkennung ist bereit für den Einsatz.") print("\nNeue Funktionalitäten:") print("+ Hash-basierte Duplikatserkennung im gesamten Projekt") print("+ Automatische Zuordnung bei Hash-Match") print("+ Intelligente Dateinamen-Generierung (datei_1.xml Format)") print("+ Integration in Drag&Drop und Kontextmenü") print("+ Benutzerfreundliche Dateiname-Auswahl-Dialoge") except Exception as e: print(f"\n[ERROR] Test fehlgeschlagen: {e}") import traceback traceback.print_exc() sys.exit(1)