mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
369 lines
13 KiB
Python
369 lines
13 KiB
Python
from typing import Optional
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from qtpy.QtWidgets import QLabel, QPushButton, QWidget
|
|
|
|
from bec_widgets.widgets.containers.layout_manager.layout_manager import LayoutManagerWidget
|
|
|
|
|
|
class MockWidgetHandler:
|
|
def create_widget(self, widget_type: str) -> Optional[QWidget]:
|
|
if widget_type == "ButtonWidget":
|
|
return QPushButton()
|
|
elif widget_type == "LabelWidget":
|
|
return QLabel()
|
|
else:
|
|
return None
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_widget_handler():
|
|
handler = MockWidgetHandler()
|
|
with patch(
|
|
"bec_widgets.widgets.containers.layout_manager.layout_manager.widget_handler", handler
|
|
):
|
|
yield handler
|
|
|
|
|
|
@pytest.fixture
|
|
def layout_manager(qtbot, mock_widget_handler):
|
|
widget = LayoutManagerWidget()
|
|
qtbot.addWidget(widget)
|
|
qtbot.waitExposed(widget)
|
|
yield widget
|
|
|
|
|
|
def test_add_widget_empty_position(layout_manager):
|
|
"""Test adding a widget to an empty position without shifting."""
|
|
btn1 = QPushButton("Button 1")
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn1
|
|
assert layout_manager.widget_positions[btn1] == (0, 0, 1, 1)
|
|
assert layout_manager.position_widgets[(0, 0)] == btn1
|
|
|
|
|
|
def test_add_widget_occupied_position(layout_manager):
|
|
"""Test adding a widget to an occupied position with shifting (default direction right)."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
layout_manager.add_widget(btn2, row=0, col=0) # This should shift btn1 to the right
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn2
|
|
assert layout_manager.get_widget(0, 1) == btn1
|
|
assert layout_manager.widget_positions[btn2] == (0, 0, 1, 1)
|
|
assert layout_manager.widget_positions[btn1] == (0, 1, 1, 1)
|
|
|
|
|
|
def test_add_widget_directional_shift_down(layout_manager):
|
|
"""Test adding a widget to an occupied position but shifting down instead of right."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
btn3 = QPushButton("Button 3")
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
layout_manager.add_widget(btn2, row=0, col=0) # Shifts btn1 to the right by default
|
|
|
|
# Now add btn3 at (0,1) but shift direction is down, so it should push btn1 down.
|
|
layout_manager.add_widget(btn3, row=0, col=1, shift_direction="down")
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn2
|
|
assert layout_manager.get_widget(0, 1) == btn3
|
|
assert layout_manager.get_widget(1, 1) == btn1
|
|
|
|
|
|
def test_remove_widget_by_position(layout_manager):
|
|
"""Test removing a widget by specifying its row and column."""
|
|
btn1 = QPushButton("Button 1")
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
|
|
layout_manager.remove(row=0, col=0)
|
|
|
|
assert layout_manager.get_widget(0, 0) is None
|
|
assert btn1 not in layout_manager.widget_positions
|
|
|
|
|
|
def test_move_widget_with_shift(layout_manager):
|
|
"""Test moving a widget to an occupied position, triggering a shift."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
btn3 = QPushButton("Button 3")
|
|
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
layout_manager.add_widget(btn2, row=0, col=1)
|
|
layout_manager.add_widget(btn3, row=1, col=0)
|
|
|
|
layout_manager.move_widget(old_row=0, old_col=0, new_row=0, new_col=1, shift_direction="right")
|
|
|
|
assert layout_manager.get_widget(0, 1) == btn1
|
|
assert layout_manager.get_widget(0, 2) == btn2
|
|
assert layout_manager.get_widget(1, 0) == btn3
|
|
|
|
|
|
def test_move_widget_without_shift(layout_manager):
|
|
"""Test moving a widget to an occupied position without shifting."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
layout_manager.add_widget(btn2, row=0, col=1)
|
|
|
|
with pytest.raises(ValueError) as exc_info:
|
|
layout_manager.move_widget(old_row=0, old_col=0, new_row=0, new_col=1, shift=False)
|
|
|
|
assert "Position (0, 1) is already occupied." in str(exc_info.value)
|
|
|
|
|
|
def test_change_layout_num_cols(layout_manager):
|
|
"""Test changing the layout by specifying only the number of columns."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
btn3 = QPushButton("Button 3")
|
|
btn4 = QPushButton("Button 4")
|
|
|
|
layout_manager.add_widget(btn1)
|
|
layout_manager.add_widget(btn2)
|
|
layout_manager.add_widget(btn3)
|
|
layout_manager.add_widget(btn4)
|
|
|
|
layout_manager.change_layout(num_cols=2)
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn1
|
|
assert layout_manager.get_widget(0, 1) == btn2
|
|
assert layout_manager.get_widget(1, 0) == btn3
|
|
assert layout_manager.get_widget(1, 1) == btn4
|
|
|
|
|
|
def test_change_layout_num_rows(layout_manager):
|
|
"""Test changing the layout by specifying only the number of rows."""
|
|
btn_list = [QPushButton(f"Button {i}") for i in range(1, 7)]
|
|
for btn in btn_list:
|
|
layout_manager.add_widget(btn)
|
|
|
|
layout_manager.change_layout(num_rows=3)
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn_list[0]
|
|
assert layout_manager.get_widget(0, 1) == btn_list[1]
|
|
assert layout_manager.get_widget(1, 0) == btn_list[2]
|
|
assert layout_manager.get_widget(1, 1) == btn_list[3]
|
|
assert layout_manager.get_widget(2, 0) == btn_list[4]
|
|
assert layout_manager.get_widget(2, 1) == btn_list[5]
|
|
|
|
|
|
def test_shift_all_widgets(layout_manager):
|
|
"""Test shifting all widgets down and then up."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
layout_manager.add_widget(btn2, row=0, col=1)
|
|
|
|
# Shift all down
|
|
layout_manager.shift_all_widgets(direction="down")
|
|
|
|
assert layout_manager.get_widget(1, 0) == btn1
|
|
assert layout_manager.get_widget(1, 1) == btn2
|
|
|
|
# Shift all up
|
|
layout_manager.shift_all_widgets(direction="up")
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn1
|
|
assert layout_manager.get_widget(0, 1) == btn2
|
|
|
|
|
|
def test_add_widget_auto_position(layout_manager):
|
|
"""Test adding widgets without specifying row and column."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1)
|
|
layout_manager.add_widget(btn2)
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn1
|
|
assert layout_manager.get_widget(0, 1) == btn2
|
|
|
|
|
|
def test_clear_layout(layout_manager):
|
|
"""Test clearing the entire layout."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
layout_manager.add_widget(btn1)
|
|
layout_manager.add_widget(btn2)
|
|
|
|
layout_manager.clear_layout()
|
|
|
|
assert layout_manager.get_widget(0, 0) is None
|
|
assert layout_manager.get_widget(0, 1) is None
|
|
assert len(layout_manager.widget_positions) == 0
|
|
|
|
|
|
def test_add_widget_with_span(layout_manager):
|
|
"""Test adding a widget with rowspan and colspan."""
|
|
btn1 = QPushButton("Button 1")
|
|
layout_manager.add_widget(btn1, row=0, col=0, rowspan=2, colspan=2)
|
|
|
|
assert layout_manager.widget_positions[btn1] == (0, 0, 2, 2)
|
|
|
|
|
|
def test_add_widget_overlap_with_span(layout_manager):
|
|
"""
|
|
Test adding a widget that overlaps with an existing widget's span.
|
|
The code will attempt to shift widgets accordingly.
|
|
"""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1, row=0, col=0, rowspan=2, colspan=1)
|
|
|
|
layout_manager.add_widget(btn2, row=1, col=1, shift_direction="right")
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn1
|
|
assert layout_manager.widget_positions[btn1] == (0, 0, 2, 1)
|
|
assert layout_manager.get_widget(1, 1) == btn2
|
|
assert layout_manager.widget_positions[btn2] == (1, 1, 1, 1)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"position, btn3_coords",
|
|
[("left", (1, 0)), ("right", (1, 2)), ("top", (0, 1)), ("bottom", (2, 1))],
|
|
)
|
|
def test_add_widget_relative(layout_manager, position, btn3_coords):
|
|
"""Test adding a widget relative to an existing widget using parameterized data."""
|
|
expected_row, expected_col = btn3_coords
|
|
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
btn3 = QPushButton("Button 3")
|
|
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
layout_manager.add_widget(btn2, row=1, col=1)
|
|
|
|
layout_manager.add_widget_relative(btn3, reference_widget=btn2, position=position)
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn1
|
|
assert layout_manager.get_widget(1, 1) == btn2
|
|
assert layout_manager.get_widget(expected_row, expected_col) == btn3
|
|
|
|
|
|
def test_add_widget_relative_invalid_position(layout_manager):
|
|
"""Test adding a widget relative to an existing widget with an invalid position."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1, row=1, col=1)
|
|
with pytest.raises(ValueError) as exc_info:
|
|
layout_manager.add_widget_relative(btn2, reference_widget=btn1, position="invalid_position")
|
|
|
|
assert "Invalid position. Choose from 'left', 'right', 'top', 'bottom'." in str(exc_info.value)
|
|
btn2.deleteLater()
|
|
|
|
|
|
def test_add_widget_relative_to_nonexistent_widget(layout_manager):
|
|
"""Test adding a widget relative to a widget that does not exist in the layout."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
with pytest.raises(ValueError) as exc_info:
|
|
layout_manager.add_widget_relative(btn2, reference_widget=btn1, position="left")
|
|
|
|
assert "Reference widget not found in layout." in str(exc_info.value)
|
|
btn1.deleteLater()
|
|
btn2.deleteLater()
|
|
|
|
|
|
def test_add_widget_relative_with_shift(layout_manager):
|
|
"""Test adding a widget relative to an existing widget with shifting."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
btn3 = QPushButton("Button 3")
|
|
|
|
layout_manager.add_widget(btn1, row=1, col=1)
|
|
layout_manager.add_widget(btn2, row=1, col=0)
|
|
|
|
layout_manager.add_widget_relative(
|
|
btn3, reference_widget=btn1, position="left", shift_direction="right"
|
|
)
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn3
|
|
assert layout_manager.get_widget(1, 1) == btn2
|
|
assert layout_manager.get_widget(0, 1) == btn1
|
|
|
|
|
|
def test_move_widget_by_object(layout_manager):
|
|
"""Test moving a widget using the widget object."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1)
|
|
layout_manager.add_widget(btn2, row=0, col=1)
|
|
|
|
layout_manager.move_widget_by_object(btn1, new_row=1, new_col=1)
|
|
|
|
# the grid is reindex after each move, so the new positions are (0,0) and (1,0), because visually there is only one column
|
|
assert layout_manager.get_widget(1, 0) == btn1
|
|
assert layout_manager.get_widget(0, 0) == btn2
|
|
|
|
|
|
def test_move_widget_by_coords(layout_manager):
|
|
"""Test moving a widget using its current coordinates."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1)
|
|
layout_manager.add_widget(btn2, row=0, col=1)
|
|
|
|
layout_manager.move_widget_by_coords(0, 0, 1, 0, shift_direction="down")
|
|
|
|
assert layout_manager.get_widget(1, 0) == btn1
|
|
assert layout_manager.get_widget(0, 1) == btn2
|
|
|
|
|
|
def test_change_layout_no_arguments(layout_manager):
|
|
"""Test changing the layout with no arguments (should do nothing)."""
|
|
btn1 = QPushButton("Button 1")
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
|
|
layout_manager.change_layout()
|
|
|
|
assert layout_manager.get_widget(0, 0) == btn1
|
|
assert len(layout_manager.widget_positions) == 1
|
|
|
|
|
|
def test_remove_nonexistent_widget(layout_manager):
|
|
"""Test removing a widget that doesn't exist in the layout."""
|
|
with pytest.raises(ValueError) as exc_info:
|
|
layout_manager.remove(row=0, col=0)
|
|
|
|
assert "No widget found at position (0, 0)." in str(exc_info.value)
|
|
|
|
|
|
def test_reindex_grid_after_removal(layout_manager):
|
|
"""Test reindexing the grid after removing a widget."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
layout_manager.add_widget(btn1)
|
|
layout_manager.add_widget(btn2, row=0, col=1)
|
|
|
|
layout_manager.remove_widget(btn1)
|
|
layout_manager.reindex_grid()
|
|
|
|
# After removal and reindex, btn2 should shift to (0,0)
|
|
assert layout_manager.get_widget(0, 0) == btn2
|
|
assert layout_manager.widget_positions[btn2] == (0, 0, 1, 1)
|
|
|
|
|
|
def test_shift_all_widgets_up_at_top_row(layout_manager):
|
|
"""Test shifting all widgets up when they are already at the top row."""
|
|
btn1 = QPushButton("Button 1")
|
|
btn2 = QPushButton("Button 2")
|
|
|
|
layout_manager.add_widget(btn1, row=0, col=0)
|
|
layout_manager.add_widget(btn2, row=0, col=1)
|
|
|
|
# Shifting up should cause an error since widgets can't move above row 0
|
|
with pytest.raises(ValueError) as exc_info:
|
|
layout_manager.shift_all_widgets(direction="up")
|
|
|
|
assert "Shifting widgets out of grid boundaries." in str(exc_info.value)
|