#!/usr/bin/env python3 """ Test específico para demostrar casos donde el hash detecta cambios que el método tradicional (tiempo + tamaño) podría perder. """ import os import json import hashlib import tempfile import time def calculate_file_hash(filepath): """Calcula el hash SHA256 de un archivo.""" try: sha256_hash = hashlib.sha256() with open(filepath, "rb") as f: for chunk in iter(lambda: f.read(4096), b""): sha256_hash.update(chunk) return sha256_hash.hexdigest() except Exception as e: print(f"Error calculando hash de {filepath}: {e}") return None def test_subtle_changes(): """Demuestra detección de cambios sutiles que mantienen el mismo tamaño.""" print("=== Test: Cambios Sutiles con Mismo Tamaño ===\n") with tempfile.TemporaryDirectory() as temp_dir: xml_file = os.path.join(temp_dir, "test.xml") # Crear contenido original de exactamente el mismo tamaño original = """ MotorControl_01 Active """ # Crear contenido modificado del mismo tamaño (cambiar solo algunos caracteres) modified = """ MotorControl_02 Active """ # Verificar que tienen el mismo tamaño assert len(original) == len( modified ), "Los contenidos deben tener el mismo tamaño" # Paso 1: Crear archivo original with open(xml_file, "w", encoding="utf-8") as f: f.write(original) original_hash = calculate_file_hash(xml_file) original_size = os.path.getsize(xml_file) original_mtime = os.path.getmtime(xml_file) print(f"1. Archivo original:") print(f" Contenido: MotorControl_01") print(f" Hash: {original_hash[:16]}...") print(f" Tamaño: {original_size} bytes") # Simular JSON con metadatos json_data = { "source_xml_hash": original_hash, "source_xml_size": original_size, "source_xml_mod_time": original_mtime, } # Paso 2: Esperar un poco y modificar archivo manteniendo tamaño time.sleep(0.1) # Pequeña pausa with open(xml_file, "w", encoding="utf-8") as f: f.write(modified) # Restaurar tiempo de modificación original os.utime(xml_file, (original_mtime, original_mtime)) new_hash = calculate_file_hash(xml_file) new_size = os.path.getsize(xml_file) new_mtime = os.path.getmtime(xml_file) print(f"\n2. Archivo modificado:") print(f" Contenido: MotorControl_02") print(f" Hash: {new_hash[:16]}...") print(f" Tamaño: {new_size} bytes") print( f" Tiempo: {'Igual' if abs(new_mtime - original_mtime) < 0.001 else 'Diferente'}" ) # Paso 3: Comparar métodos de detección print(f"\n3. Detección de cambios:") # Método tradicional time_match = abs(new_mtime - json_data["source_xml_mod_time"]) < 0.001 size_match = new_size == json_data["source_xml_size"] traditional_detects_change = not (time_match and size_match) # Método por hash hash_detects_change = new_hash != json_data["source_xml_hash"] print(f" Método tradicional:") print(f" Tiempo coincide: {time_match}") print(f" Tamaño coincide: {size_match}") print(f" Detecta cambio: {traditional_detects_change}") print(f" Método por hash:") print(f" Hash coincide: {new_hash == json_data['source_xml_hash']}") print(f" Detecta cambio: {hash_detects_change}") # Resultado print(f"\n4. Resultado:") if not traditional_detects_change and hash_detects_change: print(f" 🎯 HASH DETECTÓ CAMBIO que método tradicional PERDIÓ") print(f" ✅ Sin hash: archivo NO se regeneraría (ERROR)") print(f" ✅ Con hash: archivo SÍ se regenerará (CORRECTO)") elif traditional_detects_change and hash_detects_change: print(f" ✅ Ambos métodos detectaron el cambio correctamente") else: print( f" ℹ️ Resultado: tradicional={traditional_detects_change}, hash={hash_detects_change}" ) return not traditional_detects_change and hash_detects_change def test_same_size_different_content(): """Test con contenidos completamente diferentes pero mismo tamaño.""" print("\n" + "=" * 50) print("=== Test: Contenido Diferente, Mismo Tamaño ===\n") with tempfile.TemporaryDirectory() as temp_dir: xml_file = os.path.join(temp_dir, "test.xml") # Contenidos de igual longitud pero diferentes content1 = "AAAAAAAAAA" # 33 chars content2 = "BBBBBBBBBB" # 33 chars assert len(content1) == len(content2), "Deben tener igual tamaño" # Crear archivo con contenido 1 with open(xml_file, "w", encoding="utf-8") as f: f.write(content1) hash1 = calculate_file_hash(xml_file) size1 = os.path.getsize(xml_file) mtime1 = os.path.getmtime(xml_file) # Cambiar a contenido 2 manteniendo tiempo time.sleep(0.1) with open(xml_file, "w", encoding="utf-8") as f: f.write(content2) os.utime(xml_file, (mtime1, mtime1)) hash2 = calculate_file_hash(xml_file) size2 = os.path.getsize(xml_file) mtime2 = os.path.getmtime(xml_file) print(f"Contenido 1: {content1[:20]}...") print(f"Contenido 2: {content2[:20]}...") print(f"Tamaños: {size1} = {size2} ({'✓' if size1 == size2 else '✗'})") print(f"Tiempos: {'iguales' if abs(mtime2 - mtime1) < 0.001 else 'diferentes'}") print(f"Hashes: {'iguales' if hash1 == hash2 else 'diferentes'}") would_skip_traditional = (size1 == size2) and (abs(mtime2 - mtime1) < 0.001) would_skip_hash = hash1 == hash2 print( f"\nSin hash: {'SALTARÍA procesamiento' if would_skip_traditional else 'procesaría'}" ) print( f"Con hash: {'saltaría procesamiento' if would_skip_hash else 'PROCESARÍA'}" ) if would_skip_traditional and not would_skip_hash: print("🎯 El hash evita saltar un archivo que SÍ cambió") return True return False if __name__ == "__main__": print("Ejecutando tests de detección de cambios por hash...\n") test1_result = test_subtle_changes() test2_result = test_same_size_different_content() print("\n" + "=" * 50) print("=== RESUMEN ===") print( f"Test 1 (cambios sutiles): {'HASH ÚTIL' if test1_result else 'ambos métodos iguales'}" ) print( f"Test 2 (mismo tamaño): {'HASH ÚTIL' if test2_result else 'ambos métodos iguales'}" ) if test1_result or test2_result: print("\n✅ El hash SHA256 mejora la detección de cambios") print("✅ Evita regeneraciones innecesarias Y perdida de cambios reales") else: print("\n✓ Ambos métodos funcionaron igual en estos tests")