import sys import pathlib sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent)) import os import xml.etree.ElementTree as ET import pytest from enhanced_mcm_generator import EnhancedMCMGenerator def _canonicalize_xml(path: str) -> bytes: """Return a canonicalised representation of an L5X / XML file. The function removes volatile attributes (e.g. ExportDate) and sorts attributes of every element so the resulting byte string is stable across Python runs and operating systems. """ tree = ET.parse(path) root = tree.getroot() # Remove volatile attributes that change on every export (present on many elements) for elem in root.iter(): elem.attrib.pop("ExportDate", None) # Recursively sort attributes to obtain a deterministic ordering def _sort_attrs(elem: ET.Element): if elem.attrib: # Convert to list with sorted items to keep ElementTree stable sorted_items = sorted(elem.attrib.items()) elem.attrib.clear() elem.attrib.update(sorted_items) for child in elem: _sort_attrs(child) _sort_attrs(root) # Normalise text nodes: strip leading/trailing whitespace so that # cosmetic indentation inside elements does not cause false # differences. for elem in root.iter(): if elem.text is not None: elem.text = elem.text.strip() # ElementTree does not guarantee attribute ordering when converting to # string, but because we have manually re-inserted sorted attributes we # get a deterministic output here. return ET.tostring(root, encoding="utf-8") @pytest.mark.regression def test_generated_project_matches_golden(tmp_path): """Generate the project and compare it against the golden reference. If this test fails, a refactor has changed the *semantic* XML output. Check the diff to decide whether the change is intended or not. """ project_name = "MCM04_Chute_Load" # 1. Run the generator to build a fresh project under the temporary dir generator = EnhancedMCMGenerator(project_name, excel_file="Data.xlsx") assert generator.load_and_process_data(), "Failed to load/process Excel data" output_path = generator.generate_complete_project() # 2. Compare with the golden file golden_path = os.path.join( "generated_projects", "MCM04_Chute_Load_To_Compare_Against.L5X" ) assert os.path.exists(golden_path), "Golden file is missing" assert _canonicalize_xml(output_path) == _canonicalize_xml( golden_path ), "Generated project differs from golden reference"