Merge branch 'tests' into 'master'

Tests

See merge request augustin_s/grum!5
This commit is contained in:
2023-01-24 16:21:01 +00:00
5 changed files with 475 additions and 2 deletions

28
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,28 @@
stages:
- Test
tests:
stage: Test
variables:
QT_QPA_PLATFORM: "offscreen"
XDG_RUNTIME_DIR: "/tmp/runtime-root"
script:
- pip install pytest pytest-random-order pytest-cov
- pip install -e ./
- pip install PyQtWebEngine
- apt-get update
- apt-get install -y ffmpeg libnss3 libxcomposite1 libxtst6
- python -m unittest discover -f ./tests
- coverage run --source=./grum -m unittest discover -f ./tests
- coverage report
- coverage xml
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
artifacts:
reports:
cobertura: coverage.xml

View File

@ -51,7 +51,7 @@ class MainWindow(QMainWindow):
self.setCentralWidget(splitter)
rst = RPCServerThread(host, port, doc_title_suffix=title)
self.rst = rst = RPCServerThread(host, port, doc_title_suffix=title)
rst.start()
rst.server.register_function(self.new_plot)
rst.server.register_function(self.append_data)

View File

@ -1,5 +1,9 @@
from PyQt5.QtCore import QUrl
from PyQt5.QtWebKitWidgets import QWebView
try:
from PyQt5.QtWebKitWidgets import QWebView
except ImportError:
from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView
class WebView(QWebView):

239
tests/test_mainwin.py Normal file
View File

@ -0,0 +1,239 @@
# import pytest
import sys
import unittest
from math import isclose
# from parameterized import parameterized
from unittest import mock
from PyQt5.QtTest import QSignalSpy
from PyQt5.QtWidgets import QApplication, QAction, QListWidget
from grum.cli import main
from grum.dictlist.dictlistitem import DictListItem
from grum.dictlist import DictList
from grum import ctrl_c, theme, assets
from grum.mainwin import MainWindow
from grum.mdi import MDIArea, MDISubMultiPlot, MDISubPlot
from grum.menus import BarMenu
from grum.menus.rclickmenu import RClickMenu
from grum.plotdesc import PlotDescription
from grum.rpc import RPCServerThread
class TestViewUnit(unittest.TestCase):
def setUp(self) -> None:
print("setup")
self.app = QApplication(sys.argv)
theme.apply(self.app)
# ctrl_c.setup(self.app)
self.mw = MainWindow(add_examples=True)
self.mw.show()
def tearDown(self) -> None:
print("teardown")
self.mw.rst.wait_for_stop()
self.app.quit()
print("app quit called")
del self.mw
del self.app
def test_defaults(self):
mw = self.mw
assert mw.windowTitle() == "grum"
# assert mw.windowIcon() == assets.icon()
assert isinstance(mw.lst, DictList)
for key in mw.lst.lst.items:
assert isinstance(mw.lst.lst.get(key), DictListItem)
assert isinstance(mw.lst.lst.get(key).value, PlotDescription)
assert isinstance(mw.lst.menu, RClickMenu)
assert isinstance(mw.menu_settings, BarMenu)
assert isinstance(mw.menu_settings.checkboxes["Open new plots"], QAction)
assert isinstance(mw.mdi, MDIArea)
# @parameterized.expand([["Dotted line", "r"], ["Line", "r"], ["Dots", None]])
def test_new_plot(self):
mw = self.mw
name = "plot_name"
title = "plot_title"
xlabel = "xlabel"
ylabel = "ylabel"
cfg = {"title": title, "xlabel": xlabel, "ylabel": ylabel}
spy_sig_make_new_plot = QSignalSpy(mw.sig_make_new_plot)
mw.new_plot(name, cfg=cfg)
assert name in mw.lst.lst.items.keys()
assert isinstance(mw.lst.lst.get(name).value, PlotDescription)
assert mw.lst.lst.get(name).value.title == title
assert mw.lst.lst.get(name).value.xlabel == xlabel
assert mw.lst.lst.get(name).value.ylabel == ylabel
assert mw.menu_settings.checkboxes["Open new plots"].isChecked()
assert len(spy_sig_make_new_plot) == 1 # assert called once
assert spy_sig_make_new_plot[0][0] == name # assert called with name
assert isinstance(spy_sig_make_new_plot[0][1], PlotDescription)
mw.menu_settings.checkboxes["Open new plots"].setChecked(False)
assert mw.menu_settings.checkboxes["Open new plots"].isChecked() == False
spy_sig_make_new_plot = QSignalSpy(mw.sig_make_new_plot)
mw.new_plot("new_name", cfg)
assert len(spy_sig_make_new_plot) == 0 # assert not called
mw.menu_settings.checkboxes["Open new plots"].setChecked(True)
assert mw.menu_settings.checkboxes["Open new plots"].isChecked() == True
spy_sig_make_new_plot = QSignalSpy(mw.sig_make_new_plot)
new_name_item = mw.lst.lst.get("new_name")
sub = MDISubPlot("new_name", new_name_item.value)
mw.mdi.add(sub)
mw.new_plot("new_name", cfg)
assert len(spy_sig_make_new_plot) == 0 # assert not called
def test_append_data(self):
mw = self.mw
sine_item = mw.lst.lst.get("sine")
sine_item.set_alarm = mock.MagicMock()
sine_item.value.append = mock.MagicMock()
point = (1, 2)
mw.append_data("sine", point)
sine_item.value.append.assert_called_once_with(point)
sine_item.set_alarm.assert_called_once_with(True)
sub = MDISubPlot("sine", sine_item.value)
mw.mdi.add(sub)
sub.plot.setData = mock.MagicMock()
mw.append_data("sine", point)
sub.plot.setData.assert_called_once_with(*sine_item.value.data)
print(sine_item.set_alarm.call_args)
assert sine_item.set_alarm.call_args[0][0] == False
def test_on_make_new_plot(self):
mw = self.mw
mw.make_subwin = mock.MagicMock()
args = (1, 2, "name")
kwargs = {"title": "plot_title"}
mw.on_make_new_plot(args, kwargs)
mw.make_subwin.assert_called_once_with(MDISubPlot, args, kwargs)
def test_on_dclick_list_item(self):
mw = self.mw
mw.plot_single_item = mock.MagicMock()
item = mw.lst.lst.get("sine")
mw.on_dclick_list_item(item)
mw.plot_single_item.assert_called_once_with(item)
def test_on_plot_selected(self):
mw = self.mw
sine_item = mw.lst.lst.get("sine")
cosine_item = mw.lst.lst.get("cosine")
mw.lst.setCurrentItem(sine_item)
assert mw.lst.selectedItems()
mw.plot_single_item = mock.MagicMock()
mw.on_plot_selected()
mw.plot_single_item.assert_called_once_with(sine_item)
mw.lst.setSelectionMode(QListWidget.MultiSelection)
sine_item.setSelected(True)
cosine_item.setSelected(True)
assert len(mw.lst.selectedItems()) == 2
mw.plot_multiple_items = mock.MagicMock()
mw.on_plot_selected()
mw.plot_multiple_items.assert_called_once_with([sine_item, cosine_item])
def test_plot_single_item(self):
mw = self.mw
sine_item = mw.lst.lst.get("sine")
sine_item.set_alarm = mock.MagicMock()
mw.activate_or_make_subwin = mock.MagicMock()
mw.plot_single_item(sine_item)
sine_item.set_alarm.assert_called_once_with(False)
mw.activate_or_make_subwin.assert_called_once_with(
MDISubPlot, sine_item.key, sine_item.value
)
def test_plot_multiple_items(self):
mw = self.mw
sine_item = mw.lst.lst.get("sine")
cosine_item = mw.lst.lst.get("cosine")
names = ["sine", "cosine"]
name = " | ".join(names)
items = [sine_item, cosine_item]
descs = (sine_item.value, cosine_item.value)
mw.activate_or_make_subwin = mock.MagicMock()
mw.plot_multiple_items(items)
mw.activate_or_make_subwin.assert_called_once_with(MDISubMultiPlot, name, descs)
def test_activate_or_make_subwin(self):
mw = self.mw
sine_item = mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
mw.mdi.add(sub)
cosine_item = mw.lst.get("cosine")
mw.mdi.setActiveSubWindow = mock.MagicMock()
assert mw.mdi.findSubWindow("sine")
mw.activate_or_make_subwin(MDISubPlot, sine_item.key, sine_item.value)
mw.mdi.setActiveSubWindow.assert_called_once_with(sub)
mw.make_subwin = mock.MagicMock()
mw.activate_or_make_subwin(MDISubPlot, cosine_item.key, cosine_item.value)
mw.make_subwin.assert_called_once_with(
MDISubPlot, cosine_item.key, cosine_item.value
)
def test_make_subwin(self):
mw = self.mw
cosine_item = mw.lst.get("cosine")
mw.mdi.add = mock.MagicMock()
# sub = MDISubPlot(cosine_item.key, cosine_item.value)
mw.make_subwin(MDISubPlot, cosine_item.key, cosine_item.value)
assert isinstance(mw.mdi.add.call_args[0][0], MDISubPlot)
# mw.mdi.add.assert_called_once_with(sub)

202
tests/test_mdiarea.py Normal file
View File

@ -0,0 +1,202 @@
import sys
import unittest
from unittest import mock
from grum.mainwin import MainWindow
from grum.mdi import MDIArea, MDISubMultiPlot, MDISubPlot
from grum.mdi.mdisubwin import MDISubWindow
from grum.theme import MDI_BKG
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication, QMdiArea
class TestViewUnit(unittest.TestCase):
def setUp(self) -> None:
print("setup")
self.app = QApplication(sys.argv)
self.mw = MainWindow(add_examples=True)
self.mw.show()
def tearDown(self) -> None:
print("teardown")
self.mw.rst.wait_for_stop()
self.app.quit()
print("app quit called")
del self.mw
del self.app
def test_on_cascade(self):
mdi = self.mw.mdi
mdi.enable_subwindow_view = mock.MagicMock()
mdi.cascadeSubWindows = mock.MagicMock()
mdi.menu.checkboxes["Multiple windows"].setChecked(False)
assert mdi.menu.checkboxes["Multiple windows"].isChecked() == False
mdi.on_cascade()
assert mdi.menu.checkboxes["Multiple windows"].isChecked() == True
mdi.enable_subwindow_view.assert_called_once()
mdi.cascadeSubWindows.assert_called_once()
def test_on_tile(self):
mdi = self.mw.mdi
mdi.enable_subwindow_view = mock.MagicMock()
mdi.tileSubWindows = mock.MagicMock()
mdi.menu.checkboxes["Multiple windows"].setChecked(False)
assert mdi.menu.checkboxes["Multiple windows"].isChecked() == False
mdi.on_tile()
assert mdi.menu.checkboxes["Multiple windows"].isChecked() == True
mdi.enable_subwindow_view.assert_called_once()
mdi.tileSubWindows.assert_called_once()
def test_enable_single_window_mode(self):
mdi = self.mw.mdi
mdi.enable_subwindow_view = mock.MagicMock()
mdi.closeInactiveSubWindows = mock.MagicMock()
active = mdi.activeSubWindow()
assert mdi.activeSubWindow() == None
sine_item = self.mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
mdi.addSubWindow(sub)
mdi.setActiveSubWindow(MDISubWindow("sine"))
# assert mdi.activeSubWindow() != None
mdi.enable_single_window_mode()
mdi.enable_subwindow_view.assert_called_once()
mdi.closeInactiveSubWindows.assert_called_once()
# active = mdi.activeSubWindow()
# if active:
# active.showMaximized()
# active.frame_off()
def test_enable_subwindow_view(self):
mdi = self.mw.mdi
mdi.setViewMode = mock.MagicMock()
sine_item = self.mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
mdi.addSubWindow(sub)
sub.frame_on = mock.MagicMock()
mdi.enable_subwindow_view()
mdi.setViewMode.assert_called_once_with(QMdiArea.SubWindowView)
# sub.frame_on.assert_called_once() #TODO: check this
def test_enable_tabbed_view(self):
mdi = self.mw.mdi
mdi.setViewMode = mock.MagicMock()
mdi.enable_tabbed_view()
mdi.setViewMode.assert_called_once_with(QMdiArea.TabbedView)
def test_add(self):
mdi =self.mw.mdi
sine_item = self.mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
mdi.add_multiple = mock.MagicMock()
mdi.add_single = mock.MagicMock()
assert mdi.menu.checkboxes["Single window"].isChecked() == False
mdi.add(sub)
mdi.add_multiple.assert_called_once_with(sub)
mdi.menu.checkboxes['Single window'].setChecked(True)
assert mdi.menu.checkboxes["Single window"].isChecked() == True
mdi.add(sub)
mdi.add_single.assert_called_once_with(sub)
def test_add_multiple(self):
mdi = self.mw.mdi
mdi.addSubWindow = mock.MagicMock()
sine_item = self.mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
sub.show = mock.MagicMock()
mdi.add_multiple(sub)
mdi.addSubWindow.assert_called_once()
sub.show.assert_called_once()
def test_add_single(self):
mdi = self.mw.mdi
mdi.addSubWindow = mock.MagicMock()
mdi.closeAllSubWindows = mock.MagicMock()
sine_item = self.mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
sub.showMaximized = mock.MagicMock()
sub.frame_off = mock.MagicMock()
mdi.add_single(sub)
mdi.closeAllSubWindows.assert_called_once()
mdi.addSubWindow.assert_called_once_with(sub)
sub.showMaximized.assert_called_once()
sub.frame_off.assert_called_once()
def test_paintEvent(self):
mdi = self.mw.mdi
mdi._draw_watermark = mock.MagicMock()
mdi.paintEvent('event')
mdi._draw_watermark.assert_called_once()
def test_findSubWindow(self):
mdi = self.mw.mdi
sine_item = self.mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
mdi.add(sub)
ret = mdi.findSubWindow('sine')
assert ret == sub
ret = mdi.findSubWindow('cosine')
assert ret == None
def test_closeInactiveSubWindows(self):
mdi = self.mw.mdi
sine_item = self.mw.lst.lst.get("sine")
sub = MDISubPlot("sine", sine_item.value)
mdi.add(sub)
cosine_item = self.mw.lst.lst.get("cosine")
cosine_sub = MDISubPlot("cosine", cosine_item.value)
mdi.add(cosine_sub)
sub.close = mock.MagicMock()
mdi.closeInactiveSubWindows()
active = mdi.activeSubWindow()
assert active == cosine_sub
for sub in mdi.subWindowList():
if sub != active:
sub.close.assert_called_once()