SXXXXXXX_PyUCC/tests/test_differ_no_duplication.py

172 lines
6.5 KiB
Python

"""
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'])