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

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 5aad7a5 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
RevLine 
[d5c5d3d]1import sys
2import time
3import numpy
4import logging
5import unittest
[e90988c]6import webbrowser
7
[53c771e]8from PyQt5 import QtGui, QtWidgets
9from PyQt5 import QtCore
10from PyQt5.QtTest import QTest
11from PyQt5.QtCore import Qt
[7fb471d]12from unittest.mock import MagicMock
13from unittest.mock import patch
[d5c5d3d]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
[53c771e]23if not QtWidgets.QApplication.instance():
24    app = QtWidgets.QApplication(sys.argv)
[d5c5d3d]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
[53c771e]47        self.assertIsInstance(self.widget, QtWidgets.QDialog)
[d5c5d3d]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
[53c771e]102        self.assertIsInstance(self.widget.layoutOutput,QtWidgets.QHBoxLayout)
103        self.assertIsInstance(self.widget.layoutData1,QtWidgets.QHBoxLayout)
104        self.assertIsInstance(self.widget.layoutData2,QtWidgets.QHBoxLayout)
[d5c5d3d]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 """
[e90988c]123        self.widget.manager.showHelp = MagicMock()
[d5c5d3d]124        self.widget.onHelp()
[e90988c]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])
[d5c5d3d]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 """
[0c468bf]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
[d5c5d3d]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.