"""_accept_proposal: an accepted proposal's entity id should prefer the marker's own detected "#" id (map_vision.read_marker_id, via Proposal.detected_id) over an auto-assigned letter, so ids on the board match what's actually on screen -- falling back to auto-assign (a letter, deliberately not a number, so it can't collide with or be mistaken for a real detected id -- see models.py's _next_free_id) only when there's no detection, or it collides with an id already used for that type in that group (see _accept_proposal's own docstring). Needs a real Adw/Gtk init (MainWindow.__new__ skips __init__, so no window/widgets are actually built, but Adw.init() is still required for the module import chain), same pattern proven in this repo already for headlessly exercising GTK-adjacent code. """ import gi gi.require_version("Gtk", "4.0") gi.require_version("Gdk", "4.0") gi.require_version("Adw", "1") from gi.repository import Adw # noqa: E402 Adw.init() from fenigma.app import MainWindow # noqa: E402 from fenigma.map_import import Proposal # noqa: E402 from fenigma.models import Board # noqa: E402 def _window() -> MainWindow: win = MainWindow.__new__(MainWindow) # skip __init__: no widgets needed for this win.board = Board() return win def _proposal(detected_id=None, side="hostile", sub_x=0, sub_y=0) -> Proposal: return Proposal(side=side, label="G8", sub_x=sub_x, sub_y=sub_y, unit=None, centre=(0, 0), box=(0, 0, 0, 0), detected_id=detected_id) def test_accept_uses_the_detected_id_when_present(): win = _window() win._accept_proposal(_proposal(detected_id="8")) assert win.board.targets[0].id == "8" def test_accept_falls_back_to_auto_id_with_no_detection(): win = _window() win._accept_proposal(_proposal(detected_id=None)) assert win.board.targets[0].id == "A" def test_accept_falls_back_to_auto_id_on_a_detected_id_collision(): win = _window() win._accept_proposal(_proposal(detected_id="8", sub_x=1)) win._accept_proposal(_proposal(detected_id="8", sub_x=2)) # same detected id, must not collide ids = [t.id for t in win.board.targets] assert ids[0] == "8" assert ids[1] != "8" def test_accept_keeps_target_and_ally_id_detection_in_separate_namespaces(): """A detected id colliding with an existing ALLY id shouldn't force a TARGET accept to fall back -- targets/allies are already a separate id namespace everywhere else (Board.add_target/add_ally), detected-id preference shouldn't quietly merge them.""" win = _window() win._accept_proposal(_proposal(detected_id="8", side="friendly")) win._accept_proposal(_proposal(detected_id="8", side="hostile")) assert win.board.allies[0].id == "8" assert win.board.targets[0].id == "8"