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

Last change on this file since 6b43c58 was 0c468bf, checked in by celinedurniak <celine.durniak@…>, 7 years ago

Corrected Data Operation Panel: disabling compute button when incompatible data

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