Files
AareDAQ/tests/unit/gui/test_popout_window.py
duan_jandClaude Fable 5 69b6813025 test: cover the sample-status logic, wheel guard, pop-outs, and log mirror
New tests for what the port added: status tint priority and
context-dependent chip filters on the dewar/queue model, the
right-button wheel guard (motor protection), PopoutWindow edge maths,
manual-resize fallback, close-hides behavior and DockTitleBar, the
chip drag-drop relabeling, and the console-log pop-out mirror. The
widgets' __main__ self-checks are superseded by these and removed.
Brings PR diff coverage from 70% to 81% (gate: 80%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 10:35:54 +02:00

172 lines
5.3 KiB
Python

"""PopoutWindow replaces dock floating: an additional top-level window whose
edge band resizes, whose close only hides, and whose first show lands near
the cursor. DockTitleBar puts the pop-out button next to the close box."""
from PySide6.QtCore import QEvent, QPoint, QPointF, Qt
from PySide6.QtGui import QMouseEvent
from PySide6.QtWidgets import QDockWidget, QLabel
from aare.gui.widgets.popout_window import DockTitleBar, PopoutWindow
def _window(qtbot):
w = PopoutWindow("test", QLabel("content"))
qtbot.addWidget(w)
w.resize(400, 300)
return w
def test_edges_at(qtbot):
w = _window(qtbot)
band = PopoutWindow.RESIZE_MARGIN + PopoutWindow.OUTER_GRIP
assert w._edges_at(QPoint(band - 1, 150)) == Qt.Edge.LeftEdge
assert w._edges_at(QPoint(200, band - 1)) == Qt.Edge.TopEdge
assert w._edges_at(QPoint(399, 299)) == (Qt.Edge.RightEdge | Qt.Edge.BottomEdge)
assert w._edges_at(QPoint(200, 150)) == Qt.Edge(0)
def test_cursor_for(qtbot):
w = _window(qtbot)
assert w._cursor_for(Qt.Edge.LeftEdge) == Qt.CursorShape.SizeHorCursor
assert w._cursor_for(Qt.Edge.BottomEdge) == Qt.CursorShape.SizeVerCursor
assert w._cursor_for(Qt.Edge.LeftEdge | Qt.Edge.TopEdge) == Qt.CursorShape.SizeFDiagCursor
assert w._cursor_for(Qt.Edge.RightEdge | Qt.Edge.TopEdge) == Qt.CursorShape.SizeBDiagCursor
assert w._cursor_for(Qt.Edge(0)) is None
def test_close_hides_and_keeps_geometry(qtbot):
w = _window(qtbot)
w.show()
qtbot.waitExposed(w)
w.move(120, 130)
geometry = w.geometry()
w.close()
assert not w.isVisible()
# Reopen: the first-show placement must not run again (geometry kept).
w.show()
assert w._placed
assert w.geometry() == geometry
def test_manual_resize_fallback(qtbot):
w = _window(qtbot)
w.show()
qtbot.waitExposed(w)
w.resize(400, 300)
start = w.geometry()
grab = QPointF(399.0, 299.0) # bottom-right band
press = QMouseEvent(
QEvent.Type.MouseButtonPress,
grab,
w.mapToGlobal(grab.toPoint()).toPointF(),
Qt.MouseButton.LeftButton,
Qt.MouseButton.LeftButton,
Qt.KeyboardModifier.NoModifier,
)
w.mousePressEvent(press)
if not w._manual_edges:
# The platform accepted startSystemResize; the manual path is not
# reachable here, and the press must not have moved the window.
assert w.geometry() == start
return
move_to = grab + QPointF(40.0, 25.0)
move = QMouseEvent(
QEvent.Type.MouseMove,
move_to,
w.mapToGlobal(move_to.toPoint()).toPointF(),
Qt.MouseButton.NoButton,
Qt.MouseButton.LeftButton,
Qt.KeyboardModifier.NoModifier,
)
w.mouseMoveEvent(move)
assert w.width() == start.width() + 40
assert w.height() == start.height() + 25
release = QMouseEvent(
QEvent.Type.MouseButtonRelease,
move_to,
w.mapToGlobal(move_to.toPoint()).toPointF(),
Qt.MouseButton.LeftButton,
Qt.MouseButton.NoButton,
Qt.KeyboardModifier.NoModifier,
)
w.mouseReleaseEvent(release)
assert not w._manual_edges
def test_hover_sets_resize_cursor(qtbot):
w = _window(qtbot)
w.show()
qtbot.waitExposed(w)
def hover(pos):
w.mouseMoveEvent(
QMouseEvent(
QEvent.Type.MouseMove,
pos,
w.mapToGlobal(pos.toPoint()).toPointF(),
Qt.MouseButton.NoButton,
Qt.MouseButton.NoButton,
Qt.KeyboardModifier.NoModifier,
)
)
hover(QPointF(2.0, 150.0))
assert w.cursor().shape() == Qt.CursorShape.SizeHorCursor
hover(QPointF(200.0, 150.0))
assert w.cursor().shape() == Qt.CursorShape.ArrowCursor
def test_dock_title_bar_buttons(qtbot):
dock = QDockWidget("Console Log")
qtbot.addWidget(dock)
opened = []
bar = DockTitleBar(dock, on_popout=lambda: opened.append(True))
dock.setTitleBarWidget(bar)
dock.show()
qtbot.waitExposed(dock)
qtbot.mouseClick(bar.popout_button, Qt.MouseButton.LeftButton)
assert opened == [True]
assert dock.isVisible()
def test_manual_resize_from_top_left(qtbot):
w = _window(qtbot)
w.show()
qtbot.waitExposed(w)
w.resize(400, 300)
# Drive the manual path directly; whether startSystemResize is available
# is platform luck and the top/left arithmetic deserves coverage either way.
w._manual_edges = Qt.Edge.LeftEdge | Qt.Edge.TopEdge
w._press_global = w.mapToGlobal(QPoint(2, 2))
w._press_geom = w.geometry()
move_to = QPointF(2.0 + 30.0, 2.0 + 20.0)
w.mouseMoveEvent(
QMouseEvent(
QEvent.Type.MouseMove,
move_to,
w.mapToGlobal(move_to.toPoint()).toPointF(),
Qt.MouseButton.NoButton,
Qt.MouseButton.LeftButton,
Qt.KeyboardModifier.NoModifier,
)
)
assert w.width() == 400 - 30
assert w.height() == 300 - 20
def test_paint_border_knob(qtbot, monkeypatch):
from PySide6.QtGui import QPixmap
from aare.gui.widgets import popout_window as mod
w = _window(qtbot)
# Default FRAME_L1_WIDTH "0px": render must take the paint-nothing path.
w.render(QPixmap(w.size()))
# With a visible level-1 border the painter path runs.
monkeypatch.setattr(mod, "FRAME_L1_WIDTH", "2px")
w.render(QPixmap(w.size()))