"""Project file emitter regression.""" import json from tools.epro2.kicad.pro_writer import write_kicad_pro def test_pro_carries_filename_and_root_sheet_uuid(): """The .kicad_pro must record (a) its own filename so KiCad confirms the basename matches the .kicad_sch / .kicad_pcb siblings, and (b) the root sheet uuid in the `sheets` array — that's how KiCad binds the project to the schematic root. A `sheets: []` pro file works for "open a one-off PCB" but loses cross-tool navigation in the schematic editor.""" text = write_kicad_pro("EchoEar-CoreBoard", root_sheet_uuid="abc-123") j = json.loads(text) assert j["meta"]["filename"] == "EchoEar-CoreBoard.kicad_pro" assert j["sheets"] == [["abc-123", ""]] def test_pro_without_root_uuid_emits_empty_sheets_array(): """When called for a board that has only a PCB (the SCH was DELETE_DOC), there's no root sheet uuid. Emit `sheets: []` so the project file still parses — KiCad will simply not show a schematic editor on open.""" text = write_kicad_pro("OnlyPcb", root_sheet_uuid=None) j = json.loads(text) assert j["sheets"] == [] def test_pro_top_level_keys_present_for_kicad_8(): """KiCad 8 expects certain top-level keys to exist (it'll backfill missing ones but with a "save changes?" prompt every open). Smoke-test: assert the keys that GUI reads at startup.""" text = write_kicad_pro("X") j = json.loads(text) for key in ("board", "meta", "schematic", "sheets", "net_settings"): assert key in j, f"missing top-level key: {key}" def test_duplicate_board_titles_get_distinct_basenames(): """Two BOARDs that happen to share a title (seen on the 220V power project — twin '显示板' boards in the same EPRO2 project) must end up in distinct project directories. Dedup uses the BOARD uuid prefix so each .kicad_pro/.kicad_sch/.kicad_pcb trio stays self-contained.""" from tools.epro2.kicad.__main__ import _project_basename, _group_by_board from tools.epro2.replay import Document, Project p = Project(project_uuid="p") for board_uuid, sch_uuid, pcb_uuid in [ ("b1aaaaa1", "s1aaaaa1", "p1aaaaa1"), ("b2bbbbb2", "s2bbbbb2", "p2bbbbb2"), ]: sch = Document(doc_uuid=sch_uuid, doc_type="SCH") sch.objects["META"] = {"_type": "META", "title": "显示板", "board": board_uuid} p.documents[sch_uuid] = sch pcb = Document(doc_uuid=pcb_uuid, doc_type="PCB") pcb.objects["META"] = {"_type": "META", "title": "显示板", "board": board_uuid} p.documents[pcb_uuid] = pcb boards = _group_by_board(p) assert len(boards) == 2 # Re-implement the dedup logic the CLI uses (kept inline so we exercise # exactly that path; if it changes, this test breaks loudly). base_counts: dict[str, int] = {} for slot in boards.values(): base_counts[_project_basename(slot["title"])] = ( base_counts.get(_project_basename(slot["title"]), 0) + 1 ) basenames = [ _project_basename(slot["title"]) if base_counts[_project_basename(slot["title"])] == 1 else f"{_project_basename(slot['title'])}_{board_id[:8]}" for board_id, slot in boards.items() ] assert len(set(basenames)) == 2, f"basenames collided: {basenames}"