Files
xsl-validator/test_xml_hash_duplicate_detection.py
2025-09-20 18:05:11 +02:00

264 lines
9.9 KiB
Python

#!/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 = """<?xml version="1.0" encoding="UTF-8"?>
<root>
<test>Hash-Berechnung Test</test>
</root>"""
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 = """<?xml version="1.0" encoding="UTF-8"?>
<document>
<title>Integration Test</title>
<content>Test-Inhalt für Integration</content>
</document>"""
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(f"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(f" - 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)