source: sasview/src/sas/qtgui/Calculators/UnitTesting/DataOperationUtilityTest.py @ fca1f50

ESS_GUI_Docs
Last change on this file since fca1f50 was e90988c, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Show help pages in default browser. Fixed some help links and modified unit tests. SASVIEW-800

  • Property mode set to 100644
File size: 17.6 KB
Line 
1import sys
2import time
3import numpy
4import logging
5import unittest
6import webbrowser
7
8from PyQt5 import QtGui, QtWidgets
9from PyQt5 import QtCore
10from PyQt5.QtTest import QTest
11from PyQt5.QtCore import Qt
12from unittest.mock import MagicMock
13from unittest.mock import patch
14
15from twisted.internet import threads
16
17from sas.qtgui.Calculators.DataOperationUtilityPanel import DataOperationUtilityPanel
18from sas.qtgui.Utilities.GuiUtils import *
19from sas.qtgui.Plotting.PlotterData import Data1D
20from sas.qtgui.Plotting.PlotterData import Data2D
21from sas.qtgui.MainWindow.DataState import DataState
22
23if not QtWidgets.QApplication.instance():
24    app = QtWidgets.QApplication(sys.argv)
25
26BG_COLOR_ERR = 'background-color: rgb(244, 170, 164);'
27
28class DataOperationUtilityTest(unittest.TestCase):
29    """Test the ResolutionCalculator"""
30    def setUp(self):
31        """Create the ResolutionCalculator"""
32
33        class dummy_manager(object):
34            def communicator(self):
35                return Communicate()
36
37        self.widget = DataOperationUtilityPanel(dummy_manager())
38
39    def tearDown(self):
40        """Destroy the DataOperationUtility"""
41        self.widget.close()
42        self.widget = None
43
44    def testDefaults(self):
45        """Test the GUI in its default state"""
46
47        self.assertIsInstance(self.widget, QtWidgets.QDialog)
48
49        self.assertEqual(self.widget.windowTitle(), "Data Operation")
50        self.assertEqual(self.widget.groupBox.title(), "Data Operation "
51                                                       "[ + (add); "
52                                                       "- (subtract); "
53                                                       "* (multiply); "
54                                                       "/ (divide); "
55                                                       "| (append)]")
56        # size
57        self.assertEqual(self.widget.size().height(), 425)
58        self.assertEqual(self.widget.size().width(), 951)
59
60        # content of line edits
61        self.assertEqual(self.widget.txtNumber.text(), '1.0')
62        self.assertEqual(self.widget.txtOutputData.text(), 'MyNewDataName')
63
64        # content of comboboxes and default text / index
65        self.assertFalse(self.widget.cbData1.isEditable())
66        self.assertEqual(self.widget.cbData1.count(), 1)
67        self.assertEqual(self.widget.cbData1.currentText(),
68                         'No Data Available')
69
70        self.assertFalse(self.widget.cbData2.isEditable())
71        self.assertEqual(self.widget.cbData2.count(), 1)
72        self.assertEqual(self.widget.cbData2.currentText(),
73                         'No Data Available')
74
75        self.assertFalse(self.widget.cbOperator.isEditable())
76        self.assertEqual(self.widget.cbOperator.count(), 5)
77        self.assertEqual(self.widget.cbOperator.currentText(), '+')
78        self.assertListEqual([self.widget.cbOperator.itemText(i) for i in
79                              range(self.widget.cbOperator.count())],
80                             ['+', '-', '*', '/', '|'])
81
82        # Tooltips
83        self.assertEqual(str(self.widget.cmdCompute.toolTip()), "Generate the Data "
84                                                           "and send to Data "
85                                                           "Explorer.")
86        self.assertEqual(str(self.widget.cmdClose.toolTip()), "Close this panel.")
87        self.assertEqual(str(self.widget.cmdHelp.toolTip()),
88                         "Get help on Data Operations.")
89        self.assertEqual(self.widget.txtNumber.toolTip(), "If no Data2 loaded, "
90                                                "enter a number to be "
91                                                "applied to Data1 using "
92                                                "the operator")
93        self.assertEqual(str(self.widget.cbOperator.toolTip()), "Add: +\n"
94                                                           "Subtract: - \n"
95                                                           "Multiply: *\n"
96                                                           "Divide: /\n"
97                                                           "Append(Combine): |")
98
99        self.assertFalse(self.widget.cmdCompute.isEnabled())
100        self.assertFalse(self.widget.txtNumber.isEnabled())
101
102        self.assertIsInstance(self.widget.layoutOutput,QtWidgets.QHBoxLayout)
103        self.assertIsInstance(self.widget.layoutData1,QtWidgets.QHBoxLayout)
104        self.assertIsInstance(self.widget.layoutData2,QtWidgets.QHBoxLayout)
105
106        # To store input datafiles
107        self.assertIsNone(self.widget.filenames)
108        self.assertEqual(self.widget.list_data_items, [])
109        self.assertIsNone(self.widget.data1)
110        self.assertIsNone(self.widget.data2)
111        # To store the result
112        self.assertIsNone(self.widget.output)
113        self.assertFalse(self.widget.data2OK)
114        self.assertFalse(self.widget.data1OK)
115
116        self.widget.newPlot = MagicMock()
117        self.assertTrue(self.widget.newPlot.called_once())
118        self.assertTrue(self.widget.newPlot.called_once())
119        self.assertTrue(self.widget.newPlot.called_once())
120
121    def testHelp(self):
122        """ Assure help file is shown """
123        self.widget.manager.showHelp = MagicMock()
124        self.widget.onHelp()
125        self.assertTrue(self.widget.manager.showHelp.called_once())
126        args = self.widget.manager.showHelp.call_args
127        self.assertIn('data_operator_help.html', args[0][0])
128
129    def testOnReset(self):
130        """ Test onReset function """
131        # modify gui
132        self.widget.txtNumber.setText('2.3')
133        self.widget.onReset()
134        self.assertEqual(self.widget.txtNumber.text(), '1.0')
135
136    def testOnClose(self):
137        """ test Closing window """
138        closeButton = self.widget.cmdClose
139        QTest.mouseClick(closeButton, Qt.LeftButton)
140
141
142    def testOnCompute(self):
143        """ Test onCompute function """
144
145        # define the data
146        self.widget.data1 = Data1D(x=[1.0, 2.0, 3.0], y=[11.0, 12.0, 13.0],
147                                   dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
148        self.widget.data2 = 1
149
150        # mock update of plot
151        self.widget.updatePlot = MagicMock()
152
153        # enable onCompute to run (check on data type)
154        self.widget.onCheckChosenData = MagicMock(return_value=True)
155
156        # run onCompute
157        self.widget.onCompute()
158
159        # check output:
160        # x unchanged, y incremented by 1 (=data2) and updatePlot called
161        self.assertListEqual(self.widget.output.x.tolist(),
162                             self.widget.data1.x.tolist())
163        self.assertListEqual(self.widget.output.y.tolist(), [12.0, 13.0, 14.0])
164        self.assertTrue(self.widget.updatePlot.called_once())
165
166        self.widget.onPrepareOutputData = MagicMock()
167
168        self.assertTrue(self.widget.onPrepareOutputData.called_once())
169
170    def testOnSelectData1(self):
171        """ Test ComboBox for Data1 """
172        # Case 1: no data loaded
173        self.widget.onSelectData1()
174        self.assertIsNone(self.widget.data1)
175        self.assertFalse(self.widget.data1OK)
176        self.assertFalse(self.widget.cmdCompute.isEnabled())
177
178        # Case 2: data1 is a datafile
179        self.widget.filenames = MagicMock(
180            return_value={'datafile1': 'details'})
181        self.widget.updatePlot = MagicMock()
182
183        self.widget.cbData1.addItems(['Select Data', 'datafile1'])
184        self.widget.cbData1.setCurrentIndex(self.widget.cbData1.count()-1)
185        self.assertTrue(self.widget.updatePlot.called_once())
186        # Compute button disabled if data2OK == False
187        self.assertEqual(self.widget.cmdCompute.isEnabled(), self.widget.data2OK)
188
189    def testOnSelectData2(self):
190        """ Test ComboBox for Data2 """
191        self.widget.updatePlot = MagicMock()
192        # Case 1: no data loaded
193        self.widget.onSelectData2()
194        self.assertIsNone(self.widget.data2)
195        self.assertFalse(self.widget.data2OK)
196        self.assertFalse(self.widget.cmdCompute.isEnabled())
197
198        # Case 2: when empty combobox
199        self.widget.cbData2.clear()
200        self.widget.onSelectData2()
201        self.assertFalse(self.widget.txtNumber.isEnabled())
202        self.assertFalse(self.widget.cmdCompute.isEnabled())
203
204        # Case 3: when Data2 is Number
205        # add 'Number' to combobox Data2
206        self.widget.cbData2.addItem('Number')
207        # select 'Number' for cbData2
208        self.widget.cbData2.setCurrentIndex(self.widget.cbData2.count()-1)
209        self.widget.onSelectData2()
210        # check that line edit is now enabled
211        self.assertTrue(self.widget.txtNumber.isEnabled())
212        # Compute button enabled only if data1OK True
213        self.assertEqual(self.widget.cmdCompute.isEnabled(), self.widget.data1OK)
214        self.assertIsInstance(self.widget.data2, float)
215        # call updatePlot
216        self.assertTrue(self.widget.updatePlot.called_once())
217
218        # Case 4: when Data2 is a file
219        self.widget.filenames = MagicMock(
220            return_value={'datafile2': 'details'})
221        self.widget.cbData2.addItems(['Select Data', 'Number', 'datafile2'])
222        self.widget.cbData2.setCurrentIndex(self.widget.cbData2.count() - 1)
223        self.assertTrue(self.widget.updatePlot.called_once())
224        # editing of txtNumber is disabled when Data2 is a file
225        self.assertFalse(self.widget.txtNumber.isEnabled())
226        # Compute button enabled only if data1OK True
227        self.assertEqual(self.widget.cmdCompute.isEnabled(),
228                         self.widget.data1OK)
229        # call updatePlot
230        self.assertTrue(self.widget.updatePlot.called_once())
231
232    def testUpdateCombobox(self):
233        """ Test change of contents of comboboxes for Data1 and Data2 """
234        # Create input data
235        data1 = Data1D(x=[1.0, 2.0, 3.0], y=[11.0, 12.0, 13.0],
236                       dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
237
238        data2 = Data2D(image=[0.1] * 4,
239                       qx_data=[1.0, 2.0, 3.0, 4.0],
240                       qy_data=[10.0, 11.0, 12.0, 13.0],
241                       dqx_data=[0.1, 0.2, 0.3, 0.4],
242                       dqy_data=[0.1, 0.2, 0.3, 0.4],
243                       q_data=[1, 2, 3, 4],
244                       xmin=-1.0, xmax=5.0,
245                       ymin=-1.0, ymax=15.0,
246                       zmin=-1.0, zmax=20.0)
247
248        filenames = {'datafile2': DataState(data2),
249                                 'datafile1': DataState(data1)}
250
251        # call function
252        self.widget.updateCombobox(filenames)
253
254        # check modifications of comboboxes
255        AllItemsData1 = [self.widget.cbData1.itemText(indx)
256                         for indx in range(self.widget.cbData1.count())]
257        self.assertListEqual(AllItemsData1, ['Select Data',
258                                             'datafile2',
259                                             'datafile1'])
260
261        AllItemsData2 = [self.widget.cbData2.itemText(indx)
262                         for indx in range(self.widget.cbData2.count())]
263        self.assertListEqual(AllItemsData2,
264                             ['Select Data', 'Number',
265                              'datafile2', 'datafile1'])
266
267    def testOnSelectOperator(self):
268        """ Change GUI when operator changed """
269        self.assertEqual(self.widget.lblOperatorApplied.text(),self.widget.cbOperator.currentText())
270
271        self.widget.cbOperator.setCurrentIndex(2)
272        self.assertEqual(self.widget.lblOperatorApplied.text(),
273                         self.widget.cbOperator.currentText())
274
275    def testOnInputCoefficient(self):
276        """
277        Check input of number when a coefficient is required for operation
278        """
279        # clear input for coefficient -> error
280        self.widget.txtNumber.clear()
281        # check that color of background changed to notify error
282        self.assertIn(BG_COLOR_ERR, self.widget.txtNumber.styleSheet())
283
284
285    def testCheckChosenData(self):
286        """ Test check of data compatibility """
287        # set the 2 following to True since we want to check
288        # the compatibility of dimensions
289        self.widget.data1OK = True
290        self.widget.data2OK = True
291
292        # Case 1: incompatible dimensions
293        self.widget.data1 = Data1D(x=[1.0, 2.0, 3.0], y=[11.0, 12.0, 13.0],
294                                   dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
295
296        self.widget.data2 = Data2D(image=[0.1] * 4,
297                           qx_data=[1.0, 2.0, 3.0, 4.0],
298                           qy_data=[10.0, 11.0, 12.0, 13.0],
299                           dqx_data=[0.1, 0.2, 0.3, 0.4],
300                           dqy_data=[0.1, 0.2, 0.3, 0.4],
301                           q_data=[1, 2, 3, 4],
302                           xmin=-1.0, xmax=5.0,
303                           ymin=-1.0, ymax=15.0,
304                           zmin=-1.0, zmax=20.0)
305
306        self.assertFalse(self.widget.onCheckChosenData())
307
308        # Case 2 : compatible 1 dimension
309        self.widget.data1 = Data1D(x=[1.0, 2.0, 3.0], y=[11.0, 12.0, 13.0],
310                                   dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
311
312        self.widget.data2 = Data1D(x=[1.0, 2.0, 3.0], y=[1.0, 2.0, 3.0],
313                                   dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
314
315        self.assertTrue(self.widget.onCheckChosenData())
316
317        # Case 3: compatible 2 dimension
318        self.widget.data1 = Data2D(image=[0.1] * 4,
319                                   qx_data=[1.0, 2.0, 3.0, 4.0],
320                                   qy_data=[10.0, 11.0, 12.0, 13.0],
321                                   dqx_data=[0.1, 0.2, 0.3, 0.4],
322                                   dqy_data=[0.1, 0.2, 0.3, 0.4],
323                                   q_data=[1, 2, 3, 4],
324                                   xmin=-1.0, xmax=5.0,
325                                   ymin=-1.0, ymax=15.0,
326                                   zmin=-1.0, zmax=20.0)
327
328        self.widget.data2 = Data2D(image=[0.1] * 4,
329                                   qx_data=[1.0, 2.0, 3.0, 4.0],
330                                   qy_data=[10.0, 11.0, 12.0, 13.0],
331                                   dqx_data=[0.1, 0.2, 0.3, 0.4],
332                                   dqy_data=[0.1, 0.2, 0.3, 0.4],
333                                   q_data=[1, 2, 3, 4],
334                                   xmin=-1.0, xmax=5.0,
335                                   ymin=-1.0, ymax=15.0,
336                                   zmin=-1.0, zmax=20.0)
337
338        self.assertTrue(self.widget.onCheckChosenData())
339
340        # Case 4: Different 1D
341        self.widget.data1 = Data1D(x=[1.0, 2.0, 3.0], y=[11.0, 12.0, 13.0],
342                                   dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
343
344        self.widget.data2 = Data1D(x=[0.0, 1.0, 2.0], y=[1.0, 2.0, 3.0],
345                                   dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
346
347        self.assertFalse(self.widget.onCheckChosenData())
348
349        # Case 5: Data2 is a Number
350        self.widget.cbData2.clear()
351        self.widget.cbData2.addItem('Number')
352        self.widget.cbData2.setCurrentIndex(0)
353        self.assertEqual(self.widget.cbData2.currentText(), 'Number')
354        self.assertTrue(self.widget.onCheckChosenData())
355
356    def testOnCheckOutputName(self):
357        """ Test OutputName for result of operation """
358        self.widget.txtOutputData.clear()
359        self.assertFalse(self.widget.onCheckOutputName())
360
361        self.widget.list_data_items = ['datafile1', 'datafile2']
362        self.widget.txtOutputData.setText('datafile0')
363        self.assertTrue(self.widget.onCheckOutputName())
364        self.assertIn('', self.widget.txtOutputData.styleSheet())
365
366        self.widget.txtOutputData.clear()
367        self.widget.txtOutputData.setText('datafile1')
368        self.assertFalse(self.widget.onCheckOutputName())
369        self.assertIn(BG_COLOR_ERR, self.widget.txtOutputData.styleSheet())
370
371    def testFindId(self):
372        """ Test function to find id of file in list of filenames"""
373        data_for_id = Data1D(x=[1.0, 2.0, 3.0], y=[11.0, 12.0, 13.0],
374                                   dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
375
376        self.widget.filenames = {'datafile2': DataState(data_for_id),
377                                 'datafile1': DataState(data_for_id)}
378
379        id_out = self.widget._findId('datafile2')
380        self.assertEqual(id_out, 'datafile2')
381
382    def testExtractData(self):
383        """
384        Test function to extract data to be computed from input filenames
385        """
386        data1 = Data1D(x=[1.0, 2.0, 3.0], y=[11.0, 12.0, 13.0],
387                       dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
388
389        data2 = Data2D(image=[0.1] * 4,
390                                   qx_data=[1.0, 2.0, 3.0, 4.0],
391                                   qy_data=[10.0, 11.0, 12.0, 13.0],
392                                   dqx_data=[0.1, 0.2, 0.3, 0.4],
393                                   dqy_data=[0.1, 0.2, 0.3, 0.4],
394                                   q_data=[1, 2, 3, 4],
395                                   xmin=-1.0, xmax=5.0,
396                                   ymin=-1.0, ymax=15.0,
397                                   zmin=-1.0, zmax=20.0)
398
399        self.widget.filenames = {'datafile2': DataState(data2),
400                                 'datafile1': DataState(data1)}
401
402        output1D = self.widget._extractData('datafile1')
403        self.assertTrue(isinstance(output1D, Data1D))
404
405        output2D = self.widget._extractData('datafile2')
406        self.assertIsInstance(output2D, Data2D)
407
408    # TODO
409    def testOnPrepareOutputData(self):
410        """ """
411        pass
412
413    # new_item = GuiUtils.createModelItemWithPlot(
414    #     QtCore.QVariant(self.output), name=self.txtOutputData.text())
415    # new_datalist_item = {str(self.txtOutputData.text()) + str(time.time()):
416    #                          self.output}
417    # self.communicator. \
418    #     updateModelFromDataOperationPanelSignal.emit(new_item,
419    #                                                  new_datalist_item)
420
421
422if __name__ == "__main__":
423    unittest.main()
Note: See TracBrowser for help on using the repository browser.