Adds golden_helpers (dados_from_json/serialize_infnfe, package modules so the auto's parity test and the future service can import them directly) and 6 golden cases under src/sowai_fiscal/goldens/ as package data: - caso_padrao_intra: preset Padrao, PR->PR, CSOSN 102/CFOP 5102, 2 itens - caso_padrao_inter: PR->SP, CFOP 6102, idDest=2 - caso_st_intra: Oleos, CSOSN 500/CFOP 5405, grupo ICMSSN500 (vBCSTRet/pST/vICMSSTRet) - caso_devolucao_intra: tipo_operacao devolucao, CFOP 1202 - caso_com_ub: FiscalResult com linhas ibs/cbs (grupo UB presente -- builder suporta estruturalmente mesmo com o guard de emissao do auto bloqueando hoje) - caso_fracao_centavo: qty 1.5 x 0.01, 2 linhas -- prova o arredondamento por-item (soma_itens_quantizados) contra a soma bruta Every input pins dh_emi/cnf/chave_acesso for determinism. serialize_infnfe replicates the exact SerializerConfig(xml_declaration=False, indent=None) + ns_map used by the auto's emissao.py::_serialize_nfe before signing. scripts/gen_goldens.py regenerates the .expected.xml files; test_goldens.py compares byte-for-byte (parametrized per case, readable first-divergent-byte diff on failure). Verified the comparison has real detection power by corrupting one expected file and confirming the test fails, then restored. 62 tests pass locally via `uv run pytest`.
30 lines
1.1 KiB
Python
30 lines
1.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Regenera `src/sowai_fiscal/goldens/caso_*.expected.xml` a partir dos
|
|
`caso_*.input.json` correspondentes. Uso ÚNICO hoje (fixar o corpus golden,
|
|
Task 2 do plano F1) e sempre que uma NT mudar o leiaute DE PROPÓSITO --
|
|
nunca para "corrigir" um teste vermelho sem entender por que o XML mudou.
|
|
|
|
uv run python scripts/gen_goldens.py
|
|
"""
|
|
from pathlib import Path
|
|
|
|
from sowai_fiscal.golden_helpers import dados_from_json, serialize_infnfe
|
|
|
|
_GOLDENS_DIR = Path(__file__).resolve().parent.parent / "src" / "sowai_fiscal" / "goldens"
|
|
|
|
|
|
def main() -> None:
|
|
inputs = sorted(_GOLDENS_DIR.glob("caso_*.input.json"))
|
|
if not inputs:
|
|
raise SystemExit(f"nenhum caso_*.input.json encontrado em {_GOLDENS_DIR}")
|
|
for input_path in inputs:
|
|
expected_path = input_path.with_name(input_path.name.replace(".input.json", ".expected.xml"))
|
|
dados = dados_from_json(input_path)
|
|
xml_bytes = serialize_infnfe(dados)
|
|
expected_path.write_bytes(xml_bytes)
|
|
print(f"{input_path.name} -> {expected_path.name} ({len(xml_bytes)} bytes)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|