import contextlib import io import json from pathlib import Path import tempfile import unittest from unittest.mock import patch import prepare_module_implementation_packet as packets import read_implementation_source as reader class SectionCutPacketTests(unittest.TestCase): def test_selected_packet_exposes_owner_and_current_reexport_without_declaring_acceptance(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) current = root / "docs/current" current.mkdir(parents=True) probes = root / "freecad-source/src/WebAssembly/FreeCADCoreProbe" probes.mkdir(parents=True) owner = probes / "PartSectionCutDocument.h" owner.write_text("bool executePartSectionCutDocument();\n") entry = root / "tools/part-section-cut-business-cases.mjs" entry.parent.mkdir() entry.write_text('import "./unrelated.mjs";\nexport { runFocused as runSectionCutCases } from "./part-section-cut-focus-cases.mjs";\n') focus = entry.with_name("part-section-cut-focus-cases.mjs") focus.write_text('export { runFocused } from "./part-section-cut-business-cases.mjs";\n') unrelated = entry.with_name("unrelated.mjs") unrelated.write_text("export const other = 1;\n") (current / "feature-capability-registry.json").write_text('{"records": []}') (current / "runtime-issue-ledger.json").write_text('{"issues": []}') batch = current / "batch.json" output = current / "packet.json" batch.write_text(json.dumps({"status": "ready", "batchId": "section", "selected": { "module": "Part", "tier": "business-acceptance", "family": "business-acceptance"}, "records": [["Part:desktop:Part_SectionCut", "Part_SectionCut", "acceptance_required", str(owner.relative_to(root)), 1]]})) with patch.multiple(packets, ROOT=root, BATCH_PATH=batch, OUTPUT_PATH=output, PROBE_ROOT=probes), \ patch.object(packets, "probe_sources", return_value=[]), patch.object(packets, "reconcile_failures", return_value={}), \ patch.object(packets, "module_context", return_value={}), contextlib.redirect_stdout(io.StringIO()): self.assertEqual(packets.main(), 0) packet = json.loads(output.read_text()) with patch.object(reader, "ROOT", root): paths = reader.packet_paths(packet) self.assertIn(owner, paths) self.assertIn(focus, paths) self.assertNotIn(unrelated, paths) self.assertFalse(packet["acceptanceSetup"]["ready"]) self.assertEqual(packet["acceptanceSetup"]["missingIds"], ["Part:desktop:Part_SectionCut"]) def test_case_reexports_remain_bounded_to_local_tools(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) tools = root / "tools" tools.mkdir() (root / "outside.mjs").write_text("export const value = 1;\n") for index in range(20): (tools / f"case{index}.mjs").write_text( f'export {{ value }} from "./case{index + 1}.mjs";\n' 'export { value } from "./../outside.mjs";\n') with patch.object(packets, "ROOT", root): paths = packets.case_reexport_sources(tools / "case0.mjs") self.assertEqual(len(paths), 16) self.assertTrue(all(path.parent == tools for path in paths)) if __name__ == "__main__": unittest.main()