""" Test per verificare che il differ non duplichi l'analisi dei file. Verifica che countings e metrics vengano calcolati una sola volta. """ import os import tempfile import shutil from pathlib import Path from unittest.mock import patch, MagicMock import pytest from pyucc.core.differ import BaselineManager, Differ def test_differ_no_duplicate_analysis(tmp_path): """Verifica che countings e metrics vengano calcolati solo una volta per file.""" # Crea una directory temporanea con alcuni file Python project_dir = tmp_path / "project" project_dir.mkdir() # Crea file di test file1 = project_dir / "test1.py" file1.write_text("def foo():\n return 42\n") file2 = project_dir / "test2.py" file2.write_text("def bar():\n x = 1\n return x\n") # Crea baseline manager con baselines_root temporanea baseline_dir = tmp_path / "baselines" baseline_dir.mkdir() bm = BaselineManager(str(project_dir), baselines_root=str(baseline_dir)) baseline_id = bm.create_baseline_from_dir( str(project_dir), baseline_id="test_baseline", snapshot=True, compute_sha1=True ) # Carica metadata metadata = bm.load_metadata(baseline_id) # Verifica che la baseline abbia countings e metrics assert len(metadata.files) == 2 for fm in metadata.files: # Baseline deve avere countings e metrics già calcolati assert fm.countings is not None, f"File {fm.path} dovrebbe avere countings" assert fm.metrics is not None, f"File {fm.path} dovrebbe avere metrics" # Modifica un file file1.write_text("def foo():\n # nuovo commento\n return 42\n") # Crea differ con mock per contare quante volte vengono chiamate le funzioni di analisi # Le funzioni sono importate dentro build_current_file_list, quindi devo mockare i moduli originali with patch("pyucc.core.countings_impl.analyze_file_counts") as mock_counts, patch( "pyucc.core.metrics.analyze_file_metrics" ) as mock_metrics: # Configura i mock per restituire valori realistici mock_counts.return_value = { "physical_lines": 3, "code_lines": 2, "comment_lines": 1, "blank_lines": 0, } mock_metrics.return_value = { "avg_cc": 1.0, "max_cc": 1, "func_count": 1, "mi": 100.0, } # Esegui differ differ = Differ(metadata, str(project_dir)) current_files = differ.build_current_file_list() # Verifica che build_current_file_list abbia chiamato le funzioni di analisi # Dovrebbe essere chiamato una volta per ogni file (2 file) assert ( mock_counts.call_count == 2 ), f"analyze_file_counts dovrebbe essere chiamato 2 volte, invece: {mock_counts.call_count}" assert ( mock_metrics.call_count == 2 ), f"analyze_file_metrics dovrebbe essere chiamato 2 volte, invece: {mock_metrics.call_count}" # Verifica che i file correnti abbiano countings e metrics for fm in current_files: assert fm.countings is not None, f"File {fm.path} dovrebbe avere countings" assert fm.metrics is not None, f"File {fm.path} dovrebbe avere metrics" # Reset dei mock per verificare che diff() non richiami le funzioni mock_counts.reset_mock() mock_metrics.reset_mock() # Esegui diff result = differ.diff() # VERIFICA CRITICA: diff() non dovrebbe richiamare analyze_file_counts o analyze_file_metrics # perché i dati sono già presenti nei FileMeta objects assert ( mock_counts.call_count == 0 ), f"diff() NON dovrebbe chiamare analyze_file_counts, invece chiamato {mock_counts.call_count} volte" assert ( mock_metrics.call_count == 0 ), f"diff() NON dovrebbe chiamare analyze_file_metrics, invece chiamato {mock_metrics.call_count} volte" # Verifica che il risultato contenga i dati corretti assert "pairs" in result assert len(result["pairs"]) == 2 for pair in result["pairs"]: # Ogni pair dovrebbe avere countings e metrics delta assert "baseline_countings" in pair assert "current_countings" in pair assert "baseline_metrics" in pair assert "current_metrics" in pair def test_differ_uses_precomputed_data(): """Verifica che il differ usi i dati pre-calcolati invece di ricalcolarli.""" with tempfile.TemporaryDirectory() as tmpdir: project_dir = Path(tmpdir) / "project" project_dir.mkdir() # Crea file test_file = project_dir / "example.py" test_file.write_text("def test():\n pass\n") # Crea baseline bm = BaselineManager(str(project_dir)) baseline_id = bm.create_baseline_from_dir(str(project_dir)) metadata = bm.load_metadata(baseline_id) # Verifica struttura baseline assert len(metadata.files) == 1 baseline_file = metadata.files[0] assert baseline_file.countings is not None assert baseline_file.metrics is not None # Salva i valori originali original_countings = baseline_file.countings.copy() original_metrics = baseline_file.metrics.copy() # Modifica il file test_file.write_text("def test():\n # comment\n pass\n") # Crea differ e ottieni file correnti differ = Differ(metadata, str(project_dir)) current_files = differ.build_current_file_list() # Verifica che il file corrente abbia countings e metrics assert len(current_files) == 1 current_file = current_files[0] assert current_file.countings is not None assert current_file.metrics is not None # Esegui diff result = differ.diff() # Verifica che il risultato contenga i delta assert len(result["pairs"]) == 1 pair = result["pairs"][0] # Verifica che abbia sia baseline che current data assert pair["baseline_countings"] == original_countings assert pair["current_countings"] == current_file.countings # Verifica che i delta siano calcolati assert pair["countings_delta"] is not None assert "code_lines" in pair["countings_delta"] assert "comment_lines" in pair["countings_delta"] if __name__ == "__main__": pytest.main([__file__, "-v"])