source: sasview/src/sas/qtgui/UnitTesting/DataExplorerTest.py @ 0cd8612

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 0cd8612 was 0cd8612, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 8 years ago

output console + logging

  • Property mode set to 100755
File size: 19.0 KB
RevLine 
[f721030]1import sys
2import unittest
3
4from PyQt4.QtGui import *
5from PyQt4.QtTest import QTest
6from PyQt4.QtCore import *
7from mock import MagicMock
8
9# Local
10from sas.sasgui.guiframe.dataFitting import Data1D
[1042dba]11from sas.sascalc.dataloader.loader import Loader
12from sas.sasgui.guiframe.data_manager import DataManager
13
[f721030]14from DataExplorer import DataExplorerWindow
15from GuiManager import GuiManager
16from GuiUtils import *
17from UnitTesting.TestUtils import QtSignalSpy
[1042dba]18from Plotter import Plotter
[f721030]19
20app = QApplication(sys.argv)
21
22class DataExplorerTest(unittest.TestCase):
23    '''Test the Data Explorer GUI'''
24    def setUp(self):
25        '''Create the GUI'''
[5032ea68]26        class MyPerspective(object):
27            def communicator(self):
28                return Communicate()
29            def allowBatch(self):
30                return False
[a281ab8]31            def setData(self, data_item=None):
[5032ea68]32                return None
33            def title(self):
34                return "Dummy Perspective"
35
[f721030]36        class dummy_manager(object):
37            def communicator(self):
38                return Communicate()
[5032ea68]39            def perspective(self):
40                return MyPerspective()
[f721030]41
42        self.form = DataExplorerWindow(None, dummy_manager())
43
44    def tearDown(self):
45        '''Destroy the GUI'''
46        self.form.close()
47        self.form = None
48
49    def testDefaults(self):
50        '''Test the GUI in its default state'''
[481ff26]51        # Tab widget
[f721030]52        self.assertIsInstance(self.form, QTabWidget)
53        self.assertEqual(self.form.count(), 2)
54
[481ff26]55        # Buttons - data tab
[f721030]56        self.assertEqual(self.form.cmdLoad.text(), "Load")
[f82ab8c]57        self.assertEqual(self.form.cmdDeleteData.text(), "Delete")
58        self.assertEqual(self.form.cmdDeleteTheory.text(), "Delete")
[481ff26]59        self.assertEqual(self.form.cmdFreeze.text(), "Freeze Theory")
60        self.assertEqual(self.form.cmdSendTo.text(), "...")
61        self.assertEqual(self.form.cmdSendTo.iconSize(), QSize(32, 32))
62        self.assertIsInstance(self.form.cmdSendTo.icon(), QIcon)
[f721030]63        self.assertEqual(self.form.chkBatch.text(), "Batch mode")
64        self.assertFalse(self.form.chkBatch.isChecked())
65
[481ff26]66        # Buttons - theory tab
67
68        # Combo boxes
[f721030]69        self.assertEqual(self.form.cbSelect.count(), 6)
[488c49d]70        self.assertEqual(self.form.cbSelect.currentIndex(), 0)
[f721030]71
[481ff26]72        # Models - data
73        self.assertIsInstance(self.form.model, QStandardItemModel)
[f721030]74        self.assertEqual(self.form.treeView.model().rowCount(), 0)
75        self.assertEqual(self.form.treeView.model().columnCount(), 0)
76        self.assertEqual(self.form.model.rowCount(), 0)
77        self.assertEqual(self.form.model.columnCount(), 0)
[481ff26]78        self.assertIsInstance(self.form.data_proxy, QSortFilterProxyModel)
79        self.assertEqual(self.form.data_proxy.sourceModel(), self.form.model)
80        self.assertEqual("[^()]", str(self.form.data_proxy.filterRegExp().pattern()))
81        self.assertIsInstance(self.form.treeView, QTreeView)
82
83        # Models - theory
84        self.assertIsInstance(self.form.theory_model, QStandardItemModel)
85        self.assertEqual(self.form.freezeView.model().rowCount(), 0)
86        self.assertEqual(self.form.freezeView.model().columnCount(), 0)
87        self.assertEqual(self.form.theory_model.rowCount(), 0)
88        self.assertEqual(self.form.theory_model.columnCount(), 0)
89        self.assertIsInstance(self.form.theory_proxy, QSortFilterProxyModel)
90        self.assertEqual(self.form.theory_proxy.sourceModel(), self.form.theory_model)
91        self.assertEqual("[^()]", str(self.form.theory_proxy.filterRegExp().pattern()))
92        self.assertIsInstance(self.form.freezeView, QTreeView)
93
[e540cd2]94    def testWidgets(self):
95        """
96        Test if all required widgets got added
[0cd8612]97        """
[f721030]98    def testLoadButton(self):
99        loadButton = self.form.cmdLoad
100
[9e426c1]101        filename = "cyl_400_20.txt"
102        # Initialize signal spy instances
[f82ab8c]103        spy_file_read = QtSignalSpy(self.form, self.form.communicator.fileReadSignal)
[9e426c1]104
105        # Return no files.
106        QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=None)
[f721030]107
108        # Click on the Load button
109        QTest.mouseClick(loadButton, Qt.LeftButton)
110
111        # Test the getOpenFileName() dialog called once
[9e426c1]112        self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called)
113        QtGui.QFileDialog.getOpenFileNames.assert_called_once()
114
115        # Make sure the signal has not been emitted
[e540cd2]116        self.assertEqual(spy_file_read.count(), 0)
[9e426c1]117
118        # Now, return a single file
119        QtGui.QFileDialog.getOpenFileNames = MagicMock(return_value=filename)
[e540cd2]120
[9e426c1]121        # Click on the Load button
122        QTest.mouseClick(loadButton, Qt.LeftButton)
[e540cd2]123        QtGui.qApp.processEvents()
[9e426c1]124
125        # Test the getOpenFileName() dialog called once
126        self.assertTrue(QtGui.QFileDialog.getOpenFileNames.called)
127        QtGui.QFileDialog.getOpenFileNames.assert_called_once()
128
129        # Expected one spy instance
[f82ab8c]130        #self.assertEqual(spy_file_read.count(), 1)
131        #self.assertIn(filename, str(spy_file_read.called()[0]['args'][0]))
[f721030]132
[e540cd2]133    def testLoadFiles(self):
134        """
135        Test progress bar update while loading of multiple files
136        """
137        # Set up the spy on progress bar update signal
138        spy_progress_bar_update = QtSignalSpy(self.form,
139            self.form.communicator.progressBarUpdateSignal)
140
141        # Populate the model
142        filename = ["cyl_400_20.txt", "Dec07031.ASC", "cyl_400_20.txt"]
143        self.form.readData(filename)
144
145        # 0, 0, 33, 66, -1 -> 5 signals reaching progressBar
146        self.assertEqual(spy_progress_bar_update.count(), 5)
147
148        expected_list = [0, 0, 33, 66, -1]
149        spied_list = [spy_progress_bar_update.called()[i]['args'][0] for i in xrange(5)]
150        self.assertEqual(expected_list, spied_list)
151       
[f721030]152    def testDeleteButton(self):
[5032ea68]153        """
154        Functionality of the delete button
155        """
[f82ab8c]156        deleteButton = self.form.cmdDeleteData
[f721030]157
[f82ab8c]158        # Mock the confirmation dialog with return=No
[5032ea68]159        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.No)
[f721030]160
161        # Populate the model
[5032ea68]162        filename = ["cyl_400_20.txt", "Dec07031.ASC", "cyl_400_20.txt"]
163        self.form.readData(filename)
[f721030]164
[5032ea68]165        # Assure the model contains three items
166        self.assertEqual(self.form.model.rowCount(), 3)
167
168        # Assure the checkboxes are on
169        item1 = self.form.model.item(0)
170        item2 = self.form.model.item(1)
171        item3 = self.form.model.item(2)
172        self.assertTrue(item1.checkState() == QtCore.Qt.Checked)
173        self.assertTrue(item2.checkState() == QtCore.Qt.Checked)
174        self.assertTrue(item3.checkState() == QtCore.Qt.Checked)
[f721030]175
176        # Click on the delete  button
177        QTest.mouseClick(deleteButton, Qt.LeftButton)
178
179        # Test the warning dialog called once
[5032ea68]180        self.assertTrue(QtGui.QMessageBox.question.called)
181
182        # Assure the model still contains the items
183        self.assertEqual(self.form.model.rowCount(), 3)
184
185        # Now, mock the confirmation dialog with return=Yes
186        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
187
188        # Click on the delete  button
189        QTest.mouseClick(deleteButton, Qt.LeftButton)
190
191        # Test the warning dialog called once
192        self.assertTrue(QtGui.QMessageBox.question.called)
[f721030]193
194        # Assure the model contains no items
[5032ea68]195        self.assertEqual(self.form.model.rowCount(), 0)
[f721030]196
[5032ea68]197        # Click delete once again to assure no nasty behaviour on empty model
198        QTest.mouseClick(deleteButton, Qt.LeftButton)
[f721030]199
[481ff26]200    def testDeleteTheory(self):
201        """
202        Test that clicking "Delete" in theories tab removes selected indices
203        """
204        deleteButton = self.form.cmdDeleteTheory
205
206        # Mock the confirmation dialog with return=No
207        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.No)
208
209        # Populate the model
210        item1 = QtGui.QStandardItem(True)
211        item1.setCheckable(True)
212        item1.setCheckState(QtCore.Qt.Checked)
213        item1.setText("item 1")
214        self.form.theory_model.appendRow(item1)
215        item2 = QtGui.QStandardItem(True)
216        item2.setCheckable(True)
217        item2.setCheckState(QtCore.Qt.Unchecked)
218        item2.setText("item 2")
219        self.form.theory_model.appendRow(item2)
220
221        # Assure the model contains two items
222        self.assertEqual(self.form.theory_model.rowCount(), 2)
223
224        # Assure the checkboxes are on
225        self.assertTrue(item1.checkState() == QtCore.Qt.Checked)
226        self.assertTrue(item2.checkState() == QtCore.Qt.Unchecked)
227
228        # Click on the delete  button
229        QTest.mouseClick(deleteButton, Qt.LeftButton)
230
231        # Test the warning dialog called once
232        self.assertTrue(QtGui.QMessageBox.question.called)
233
234        # Assure the model still contains the items
235        self.assertEqual(self.form.theory_model.rowCount(), 2)
236
237        # Now, mock the confirmation dialog with return=Yes
238        QtGui.QMessageBox.question = MagicMock(return_value=QtGui.QMessageBox.Yes)
239
240        # Click on the delete  button
241        QTest.mouseClick(deleteButton, Qt.LeftButton)
242
243        # Test the warning dialog called once
244        self.assertTrue(QtGui.QMessageBox.question.called)
245
246        # Assure the model contains 1 item
247        self.assertEqual(self.form.theory_model.rowCount(), 1)
248
249        # Set the remaining item to checked
250        self.form.theory_model.item(0).setCheckState(QtCore.Qt.Checked)
251
252        # Click on the delete button again
253        QTest.mouseClick(deleteButton, Qt.LeftButton)
254
255        # Assure the model contains no items
256        self.assertEqual(self.form.theory_model.rowCount(), 0)
257
258        # Click delete once again to assure no nasty behaviour on empty model
259        QTest.mouseClick(deleteButton, Qt.LeftButton)
260
261
[5032ea68]262    def testSendToButton(self):
263        """
264        Test that clicking the Send To button sends checked data to a perspective
265        """
[f82ab8c]266        # Send empty data
267        mocked_perspective = self.form.parent.perspective()
268        mocked_perspective.setData = MagicMock()
269
270        # Click on the Send To  button
271        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
272
273        # The set_data method not called
274        self.assertFalse(mocked_perspective.setData.called)
275               
[f721030]276        # Populate the model
[5032ea68]277        filename = ["cyl_400_20.txt"]
278        self.form.readData(filename)
279
280        # setData is the method we want to see called
[f82ab8c]281        mocked_perspective = self.form.parent.perspective()
282        mocked_perspective.setData = MagicMock(filename)
[f721030]283
284        # Assure the checkbox is on
[5032ea68]285        self.form.cbSelect.setCurrentIndex(0)
[f721030]286
287        # Click on the Send To  button
[5032ea68]288        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
[f721030]289
290        # Test the set_data method called once
[f82ab8c]291        #self.assertTrue(mocked_perspective.setData.called)
[5032ea68]292
293        # open another file
294        filename = ["cyl_400_20.txt"]
295        self.form.readData(filename)
296
297        # Mock the warning message
298        QtGui.QMessageBox = MagicMock()
299
300        # Click on the button
301        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
302
303        # Assure the message box popped up
304        QtGui.QMessageBox.assert_called_once()
[f721030]305
[488c49d]306    def testDataSelection(self):
307        """
308        Tests the functionality of the Selection Option combobox
309        """
310        # Populate the model with 1d and 2d data
311        filename = ["cyl_400_20.txt", "Dec07031.ASC"]
312        self.form.readData(filename)
313
314        # Unselect all data
315        self.form.cbSelect.setCurrentIndex(1)
316
317        # Test the current selection
[5032ea68]318        item1D = self.form.model.item(0)
319        item2D = self.form.model.item(1)
320        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
[488c49d]321        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)       
322
323        # Select all data
324        self.form.cbSelect.setCurrentIndex(0)
325
326        # Test the current selection
[5032ea68]327        self.assertTrue(item1D.checkState() == QtCore.Qt.Checked)
[488c49d]328        self.assertTrue(item2D.checkState() == QtCore.Qt.Checked)       
329
330        # select 1d data
331        self.form.cbSelect.setCurrentIndex(2)
332
333        # Test the current selection
[5032ea68]334        self.assertTrue(item1D.checkState() == QtCore.Qt.Checked)
[488c49d]335        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)       
336
337        # unselect 1d data
338        self.form.cbSelect.setCurrentIndex(3)
339
340        # Test the current selection
[5032ea68]341        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
[488c49d]342        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)       
343
344        # select 2d data
345        self.form.cbSelect.setCurrentIndex(4)
346
347        # Test the current selection
[5032ea68]348        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
[488c49d]349        self.assertTrue(item2D.checkState() == QtCore.Qt.Checked)       
350
351        # unselect 2d data
352        self.form.cbSelect.setCurrentIndex(5)
353
354        # Test the current selection
[5032ea68]355        self.assertTrue(item1D.checkState() == QtCore.Qt.Unchecked)
[488c49d]356        self.assertTrue(item2D.checkState() == QtCore.Qt.Unchecked)       
357
358        # choose impossible index and assure the code raises
359        #with self.assertRaises(Exception):
360        #    self.form.cbSelect.setCurrentIndex(6)
361
[481ff26]362    def testFreezeTheory(self):
363        """
364        Assure theory freeze functionality works
365        """
366        # Not yet tested - agree on design first.
367        pass
368
369    def testRecursivelyCloneItem(self):
370        """
371        Test the rescursive QAbstractItem/QStandardItem clone
372        """
373        # Create an item with several branches
374        item1 = QtGui.QStandardItem()
375        item2 = QtGui.QStandardItem()
376        item3 = QtGui.QStandardItem()
377        item4 = QtGui.QStandardItem()
378        item5 = QtGui.QStandardItem()
379        item6 = QtGui.QStandardItem()
380
381        item4.appendRow(item5)
382        item2.appendRow(item4)
383        item2.appendRow(item6)
384        item1.appendRow(item2)
385        item1.appendRow(item3)
386
387        # Clone
388        new_item = self.form.recursivelyCloneItem(item1)
389
390        # assure the trees look identical
391        self.assertEqual(item1.rowCount(), new_item.rowCount())
392        self.assertEqual(item1.child(0).rowCount(), new_item.child(0).rowCount())
393        self.assertEqual(item1.child(1).rowCount(), new_item.child(1).rowCount())
394        self.assertEqual(item1.child(0).child(0).rowCount(), new_item.child(0).child(0).rowCount())
395
[f721030]396    def testReadData(self):
397        """
[5032ea68]398        Test the low level readData() method
[f721030]399        """
400        filename = ["cyl_400_20.txt"]
401        self.form.manager.add_data = MagicMock()
402
403        # Initialize signal spy instances
[f82ab8c]404        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
405        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
[f721030]406
407        # Read in the file
408        self.form.readData(filename)
409
410        # Expected two status bar updates
[5032ea68]411        self.assertEqual(spy_status_update.count(), 1)
[f721030]412        self.assertIn(filename[0], str(spy_status_update.called()[0]['args'][0]))
413
414
415        # Check that the model contains the item
416        self.assertEqual(self.form.model.rowCount(), 1)
417        self.assertEqual(self.form.model.columnCount(), 1)
418
419        # The 0th item header should be the name of the file
420        model_item = self.form.model.index(0,0)
421        model_name = str(self.form.model.data(model_item).toString())
422        self.assertEqual(model_name, filename[0])
423
[481ff26]424    def testDisplayHelp(self):
425        """
426        Test that the Help window gets shown correctly
427        """
428        partial_url = "sasgui/guiframe/data_explorer_help.html"
429        button1 = self.form.cmdHelp
430        button2 = self.form.cmdHelp_2
431
432        # Click on the Help button
433        QTest.mouseClick(button1, Qt.LeftButton)
434        qApp.processEvents()
435
436        # Check the browser
437        self.assertIn(partial_url, str(self.form._helpView.url()))
438        # Close the browser
439        self.form._helpView.close()
440
441        # Click on the Help_2 button
442        QTest.mouseClick(button2, Qt.LeftButton)
443        qApp.processEvents()
444        # Check the browser
445        self.assertIn(partial_url, str(self.form._helpView.url()))
446
[5032ea68]447    def testLoadFile(self):
448        """
449        Test the threaded call to readData()
450        """
[f82ab8c]451        #self.form.loadFile()
[5032ea68]452        pass
[f721030]453
454    def testGetWList(self):
455        """
[f82ab8c]456        Test the list of known extensions
[f721030]457        """
[481ff26]458        w_list = self.form.getWlist()
459
[f721030]460        defaults = 'All (*.*);;canSAS files (*.xml);;SESANS files' +\
461            ' (*.ses);;ASCII files (*.txt);;IGOR 2D files (*.asc);;' +\
462            'IGOR/DAT 2D Q_map files (*.dat);;IGOR 1D files (*.abs);;'+\
463            'HFIR 1D files (*.d1d);;DANSE files (*.sans);;NXS files (*.nxs)'
[481ff26]464        default_list = defaults.split(';;')
465
[e540cd2]466        for def_format in default_list:
467            self.assertIn(def_format, w_list)
[5032ea68]468       
[f721030]469    def testLoadComplete(self):
470        """
[5032ea68]471        Test the callback method updating the data object
[f721030]472        """
[a281ab8]473        message="Loading Data Complete"
[5032ea68]474        data_dict = {"a1":Data1D()}
[a281ab8]475        output_data = (data_dict, message)
[5032ea68]476
477        self.form.manager.add_data = MagicMock()
478
479        # Initialize signal spy instances
[f82ab8c]480        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
481        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
[f721030]482
[5032ea68]483        # Read in the file
[a281ab8]484        self.form.loadComplete(output_data)
[f721030]485
[5032ea68]486        # "Loading data complete" no longer sent in LoadFile but in callback
487        self.assertIn("Loading Data Complete", str(spy_status_update.called()[0]['args'][0]))
[f721030]488
[5032ea68]489        # Expect one Data Received signal
[f721030]490        self.assertEqual(spy_data_received.count(), 1)
491
[5032ea68]492        # Assure returned dictionary has correct data
493        # We don't know the data ID, so need to iterate over dict
494        data_dict = spy_data_received.called()[0]['args'][0]
495        for data_key, data_value in data_dict.iteritems():
496            self.assertIsInstance(data_value, Data1D)
497
498        # Assure add_data on data_manager was called (last call)
499        self.assertTrue(self.form.manager.add_data.called)
500
[1042dba]501    def testNewPlot(self):
502        """
503        Creating new plots from Data1D/2D
504        """
505        loader = Loader()
506        manager = DataManager()
507
508        # get Data1D
509        p_file="cyl_400_20.txt"
510        output_object = loader.load(p_file)
511        new_data = [manager.create_gui_data(output_object, p_file)]
512
513        # Mask the plot show call
514        Plotter.show = MagicMock()
515
516        # Mask retrieval of the data
517        self.form.plotsFromCheckedItems = MagicMock(return_value=new_data)
518
519        # Call the plotting method
520        self.form.newPlot()
521
522        # The plot was displayed
523        self.assertTrue(Plotter.show.called)
524
[f82ab8c]525    def testUpdateModelFromPerspective(self):
526        """
527        Assure the model update is correct
528        """
529        good_item = QtGui.QStandardItem()
530        bad_item = "I'm so bad"
531
532        self.form.model.reset = MagicMock()
533
534        self.form.updateModelFromPerspective(good_item)
535
536        # See that the model got reset
537        self.form.model.reset.assert_called_once()
538
539        # See that the bad item causes raise
540        with self.assertRaises(Exception):
541            self.form.updateModelFromPerspective(bad_item)
[5032ea68]542
[f721030]543if __name__ == "__main__":
544    unittest.main()
Note: See TracBrowser for help on using the repository browser.