Files
templates/python/tests/test_plot_processing_qt.py

94 lines
3.8 KiB
Python

"""Reusable Qt adapter tests, runnable with PySide2 or PySide6, without a GUI app repo."""
import os
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
import time
import unittest
from dataclasses import replace
from unittest.mock import patch
from set_devices.plot_processing import Axis, Series, Snapshot, process
from set_devices.qt_ports.plot_processing import SignalProcessingPanel, PlotProcessingAttachment, QWidget
try:
from PySide6.QtWidgets import QApplication
except ImportError:
from PySide2.QtWidgets import QApplication
class ProcessingQtTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.app = QApplication.instance() or QApplication([])
def setUp(self):
self.panel = SignalProcessingPanel()
self.snapshot = Snapshot([Series("a", "A", [(0, 0), (1, 1), (2, 0)])])
self.panel.set_snapshot(self.snapshot)
def tearDown(self):
self.panel.close()
def calculate(self):
self.panel.calculate()
deadline = time.monotonic() + 5
while self.panel._job is not None and time.monotonic() < deadline:
self.app.processEvents()
time.sleep(.002)
self.assertIsNone(self.panel._job)
self.assertIsNotNone(self.panel.curve, self.panel.status.text())
def test_all_methods_are_available_and_parameter_changes_clear_result(self):
for method in ("polynomial", "linear", "pchip", "spline"):
self.panel.method.setCurrentIndex(self.panel.method.findData(method))
self.calculate()
self.assertEqual(method, self.panel.curve.request.method)
self.panel.count.setValue(self.panel.count.value() + 1)
self.assertIsNone(self.panel.curve)
self.assertFalse(self.panel.export_button.isEnabled())
def test_source_units_and_blocking_invalidate_result(self):
for changed in (replace(self.snapshot, axis=Axis("Frequency", "Hz")),
replace(self.snapshot, source="new file"),
replace(self.snapshot, x_range=(0, 1)),
replace(self.snapshot, blocked_reason="FFT")):
self.panel.set_snapshot(self.snapshot)
self.calculate()
self.panel.set_snapshot(changed)
self.assertIsNone(self.panel.curve)
self.assertFalse(self.panel.export_button.isEnabled())
self.assertFalse(self.panel.apply_button.isEnabled())
def test_late_worker_result_is_rejected_even_after_source_returns(self):
# Capture, but do not schedule, the real worker. Deliver its answer after
# the source changes away and back to the same numerical values.
with patch("set_devices.qt_ports.plot_processing.QThreadPool"):
self.panel.calculate()
job = self.panel._job
self.panel.set_snapshot(replace(self.snapshot, source="another"))
self.panel.set_snapshot(self.snapshot)
self.panel._finished(job.signature, process(job.signature), "")
self.assertIsNone(self.panel.curve)
self.assertFalse(self.panel.export_button.isEnabled())
def test_attachment_is_lazy_and_coalesces_source_notifications(self):
widget = QWidget()
calls = []
attachment = PlotProcessingAttachment(widget, lambda: calls.append(1) or self.snapshot, widget.update)
try:
for _ in range(10):
attachment.source_changed()
self.app.processEvents()
self.assertEqual([], calls)
self.assertIsNone(attachment.panel)
attachment.open()
self.assertEqual([1], calls)
for _ in range(10):
attachment.source_changed()
self.app.processEvents()
self.assertEqual([1, 1], calls)
finally:
widget.close()
if __name__ == "__main__":
unittest.main()