1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
import sys
import unittest
from unittest.mock import MagicMock, call
from AnyQt.QtWidgets import QApplication
from orangewidget.tests.base import WidgetTest
from orangewidget.utils.widgetpreview import WidgetPreview
from orangewidget.widget import OWBaseWidget, Input
from orangewidget.utils import widgetpreview
# MagicMocks have no names, so we patch Input.__call__ to use them
# as input handlers
class MockInput(Input):
def __call__(self, method):
self.handler = self.name
return method
class TestWidgetPreviewBase(WidgetTest):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.app = app = QApplication.instance()
cls.orig_sys_exit = sys.exit
cls.orig_app_exec = app.exec
cls.orig_qapplication = widgetpreview.QApplication
sys.exit = MagicMock()
widgetpreview.QApplication = MagicMock(return_value=app)
app.exec = MagicMock()
@classmethod
def tearDownClass(cls):
app = QApplication.instance()
sys.exit = cls.orig_sys_exit
app.exec = cls.orig_app_exec
widgetpreview.QApplication = cls.orig_qapplication
del cls.app
super().tearDownClass()
def setUp(self):
# Class is defined within setUp to reset mocks before each test
class MockWidget(OWBaseWidget):
name = "foo"
class Inputs:
input_int = MockInput("int1", int)
input_float1 = MockInput("float1", float, default=True)
input_float2 = MockInput("float2", float)
input_str1 = MockInput("str1", str)
input_str2 = MockInput("str2", str)
int1 = Inputs.input_int(MagicMock())
float1 = Inputs.input_float1(MagicMock())
float2 = Inputs.input_float2(MagicMock())
str1 = Inputs.input_str1(MagicMock())
str2 = Inputs.input_str2(MagicMock())
show = MagicMock()
saveSettings = MagicMock()
super().setUp()
self.widgetClass = MockWidget
sys.exit.reset_mock()
widgetpreview.QApplication.reset_mock()
self.app.exec.reset_mock()
def tearDown(self) -> None:
super().tearDown()
def widget_constructor(self):
return self.widgetClass()
class TestWidgetPreview(TestWidgetPreviewBase):
def test_widget_is_shown_and_ran(self):
w = self.widgetClass
self.app.exec.reset_mock()
previewer = WidgetPreview(self.widget_constructor)
previewer.run()
w.show.assert_called()
w.show.reset_mock()
self.app.exec.assert_called()
self.app.exec.reset_mock()
w.saveSettings.assert_called()
w.saveSettings.reset_mock()
sys.exit.assert_called()
sys.exit.reset_mock()
self.assertIsNone(previewer.widget)
previewer.run(no_exit=True)
w.show.assert_called()
w.show.reset_mock()
self.app.exec.assert_called()
self.app.exec.reset_mock()
w.saveSettings.assert_not_called()
sys.exit.assert_not_called()
self.assertIsNotNone(previewer.widget)
widget = previewer.widget
previewer.run(no_exec=True, no_exit=True)
w.show.assert_not_called()
self.app.exec.assert_not_called()
w.saveSettings.assert_not_called()
sys.exit.assert_not_called()
self.assertIs(widget, previewer.widget)
previewer.run(no_exec=True)
w.show.assert_not_called()
self.app.exec.assert_not_called()
w.saveSettings.assert_called()
sys.exit.assert_called()
self.assertIsNone(previewer.widget)
def test_single_signal(self):
w = self.widgetClass
WidgetPreview(self.widget_constructor).run(42)
w.int1.assert_called_with(42)
WidgetPreview(self.widget_constructor).run(3.14)
w.float1.assert_called_with(3.14)
self.assertEqual(w.float2.call_count, 0)
with self.assertRaises(ValueError):
WidgetPreview(self.widget_constructor).run("foo")
with self.assertRaises(ValueError):
WidgetPreview(self.widget_constructor).run([])
def test_named_signals(self):
w = self.widgetClass
WidgetPreview(self.widget_constructor).run(42, float2=2.7, str1="foo")
w.int1.assert_called_with(42)
self.assertEqual(w.float1.call_count, 0)
w.float2.assert_called_with(2.7)
w.str1.assert_called_with("foo")
self.assertEqual(w.str2.call_count, 0)
def test_multiple_runs(self):
w = self.widgetClass
previewer = WidgetPreview(self.widget_constructor)
previewer.run(42, no_exit=True)
w.int1(43)
previewer.send_signals([(44, 1), (45, 2)])
previewer.run(46, no_exit=True)
w.int1.assert_has_calls(
[call(42), call(43), call(44, 1), call(45, 2), call(46)])
class TestWidgetPreviewInternal(TestWidgetPreviewBase):
def test_find_handler_name(self):
previewer = WidgetPreview(self.widget_constructor)
previewer.create_widget()
find_name = previewer._find_handler_name
self.assertEqual(find_name(42), "int1")
self.assertEqual(find_name(3.14), "float1")
self.assertRaises(ValueError, find_name, "foo")
self.assertRaises(ValueError, find_name, [])
self.assertRaises(ValueError, find_name, [42])
self.assertEqual(find_name([(42, 1)]), "int1")
self.assertEqual(find_name([(2, 1), (3, 2)]), "int1")
self.assertEqual(find_name([(42.4, 1)]), "float1")
self.assertEqual(find_name([(42.4, 1), (5.1, 1)]), "float1")
self.assertRaises(ValueError, find_name, [("foo", 1)])
self.assertRaises(ValueError, find_name, [])
def test_data_chunks(self):
self.assertEqual(
list(WidgetPreview._data_chunks(42)),
[(42, )])
self.assertEqual(
list(WidgetPreview._data_chunks((42, 1))),
[(42, 1)])
self.assertEqual(
list(WidgetPreview._data_chunks([(42, 1), (65, 3)])),
[(42, 1), (65, 3)])
def test_create_widget(self):
previewer = WidgetPreview(self.widget_constructor)
self.assertIsNone(previewer.widget)
previewer.create_widget()
self.assertIsInstance(previewer.widget, self.widgetClass)
def test_send_signals(self):
previewer = WidgetPreview(self.widget_constructor)
previewer.create_widget()
widget = previewer.widget
previewer.send_signals(42)
widget.int1.assert_called_with(42)
widget.int1.reset_mock()
previewer.send_signals(
[(42, 1), (40, 2)],
str2="foo",
float1=[(3.14, 1), (5.1, 8)])
widget.int1.assert_has_calls([call(42, 1), call(40, 2)])
widget.str2.assert_called_with("foo")
widget.float1.assert_has_calls([call(3.14, 1), call(5.1, 8)])
if __name__ == "__main__":
unittest.main()
|