"""Poarta de regresie: codul de conversie de azi trebuie sa reproduca etalonul. Ruleaza convertorul pe balantele CSV de pe disc (FUNDATIA, MASTER), scrie xlsx-urile de initializare intr-un director temporar (nu peste cele din radacina), le anonimizeaza cu ACELEASI reguli si ACEIASI tabela ca tests/anonimizeaza_etalon.py si le compara cu tests/golden/ pe VALORI DE CELULA. Comparatia nu se face niciodata pe hash de fisier: un xlsx rescris de alta versiune de openpyxl are alti octeti cu acelasi continut. Rulare: py -m unittest discover -s tests -v """ import os import pathlib import sys import tempfile import unittest import openpyxl RADACINA = pathlib.Path(__file__).resolve().parent.parent TESTS = pathlib.Path(__file__).resolve().parent for cale in (str(RADACINA), str(TESTS)): if cale not in sys.path: sys.path.insert(0, cale) import genereaza_xlsx as generator import anonimizeaza_etalon as anonim CORESP = TESTS / "_corespondenta_anonimizare.json" GOLDEN = TESTS / "golden" FIRME = [ ("FUNDATIA", "balanta_FUNDATIA.csv", "golden_FUNDATIA_2025_12.xlsx"), ("MASTER", "balanta_MASTER.csv", "golden_MASTER_2025_12.xlsx"), ] MAX_DIFERENTE_RAPORTATE = 20 class TestRegresieEtalon(unittest.TestCase): @classmethod def setUpClass(cls): if not CORESP.exists(): raise unittest.SkipTest( "Lipseste %s (e ignorata de git). Etalonul nu se poate reproduce " "fara tabela de corespondenta - vezi docs/handoff_etapa2_convertor.md, " "sectiunea despre etalon." % CORESP ) cls.coresp = anonim.citeste_corespondenta(CORESP) cls._cwd = os.getcwd() os.chdir(str(RADACINA)) # TEMPLATE si CSV-urile sunt relative la radacina cls._tmp = tempfile.TemporaryDirectory(prefix="regresie_") tmpdir = pathlib.Path(cls._tmp.name) cls.iesiri = {} try: header = generator.citeste_header() for firma, csv_nume, golden_nume in FIRME: rows = generator.citeste_balanta(str(RADACINA / "date" / csv_nume)) out, _, _, _, _ = generator.genereaza(rows, header) brut = tmpdir / ("init_%s_2025_12.xlsx" % firma) generator.scrie_xlsx(header, out, str(brut)) anonimizat = tmpdir / ("anon_%s.xlsx" % firma) anonim.anonimizeaza_fisier(str(brut), str(anonimizat), cls.coresp) cls.iesiri[firma] = (anonimizat, GOLDEN / golden_nume) except Exception: os.chdir(cls._cwd) cls._tmp.cleanup() raise @classmethod def tearDownClass(cls): os.chdir(cls._cwd) cls._tmp.cleanup() def _verifica(self, firma): anonimizat, golden = self.iesiri[firma] self.assertTrue(golden.exists(), "lipseste etalonul %s" % golden) wb_gasit = openpyxl.load_workbook(anonimizat) wb_asteptat = openpyxl.load_workbook(golden) ws_gasit, ws_asteptat = wb_gasit.active, wb_asteptat.active nr_g = ws_gasit.max_row nc_g = ws_gasit.max_column nr_a = ws_asteptat.max_row nc_a = ws_asteptat.max_column self.assertEqual( (nr_g, nc_g), (nr_a, nc_a), "Dimensiuni diferite pentru %s: asteptat %d randuri x %d coloane, " "gasit %d randuri x %d coloane" % (golden.name, nr_a, nc_a, nr_g, nc_g), ) diferente = [] for rand in range(1, max(nr_g, nr_a) + 1): for col in range(1, max(nc_g, nc_a) + 1): gasit = ws_gasit.cell(rand, col).value asteptat = ws_asteptat.cell(rand, col).value if gasit != asteptat: diferente.append((rand, col, asteptat, gasit)) if diferente: linii = ["%d celule difera fata de %s:" % (len(diferente), golden.name)] for rand, col, asteptat, gasit in diferente[:MAX_DIFERENTE_RAPORTATE]: linii.append( " %s: rand %d, coloana %d: asteptat %r, gasit %r" % (golden.name, rand, col, asteptat, gasit) ) if len(diferente) > MAX_DIFERENTE_RAPORTATE: linii.append(" ... si alte %d celule" % (len(diferente) - MAX_DIFERENTE_RAPORTATE)) self.fail("\n".join(linii)) def test_fundatia(self): self._verifica("FUNDATIA") def test_master(self): self._verifica("MASTER") if __name__ == "__main__": unittest.main()