source: sasview/src/sas/qtgui/MainWindow/UnitTesting/DataExplorerTest.py @ 1309205b

Last change on this file since 1309205b was d9150d8, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

Delete open plots on data removal SASVIEW-958

  • Property mode set to 100644
File size: 30.6 KB
RevLine 
[f721030]1import sys
[80468f6]2import time
[f721030]3import unittest
4
[53c771e]5from PyQt5.QtGui import *
6from PyQt5.QtWidgets import *
7from PyQt5.QtTest import QTest
8from PyQt5.QtCore import *
[7fb471d]9from unittest.mock import MagicMock
10from unittest.mock import patch
[cad617b]11from mpl_toolkits.mplot3d import Axes3D
[31c5b58]12
13# set up import paths
14import path_prepare
[f721030]15
16# Local
[dc5ef15]17from sas.qtgui.Plotting.PlotterData import Data1D
[1042dba]18from sas.sascalc.dataloader.loader import Loader
[dc5ef15]19from sas.qtgui.MainWindow.DataManager import DataManager
[1042dba]20
[83eb5208]21from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
22from sas.qtgui.MainWindow.GuiManager import GuiManager
23from sas.qtgui.Utilities.GuiUtils import *
[f721030]24from UnitTesting.TestUtils import QtSignalSpy
[83eb5208]25from sas.qtgui.Plotting.Plotter import Plotter
26from sas.qtgui.Plotting.Plotter2D import Plotter2D
27import sas.qtgui.Plotting.PlotHelper as PlotHelper
[f721030]28
[80468f6]29if not QApplication.instance():
30    app = QApplication(sys.argv)
[f721030]31
32class DataExplorerTest(unittest.TestCase):
33    '''Test the Data Explorer GUI'''
34    def setUp(self):
35        '''Create the GUI'''
[5032ea68]36        class MyPerspective(object):
37            def communicator(self):
38                return Communicate()
39            def allowBatch(self):
[53c771e]40                return True
[f7d14a1]41            def setData(self, data_item=None, is_batch=False):
[5032ea68]42                return None
43            def title(self):
44                return "Dummy Perspective"
45
[f721030]46        class dummy_manager(object):
47            def communicator(self):
48                return Communicate()
[5032ea68]49            def perspective(self):
50                return MyPerspective()
[8cb6cd6]51            def workspace(self):
52                return None
[f721030]53
54        self.form = DataExplorerWindow(None, dummy_manager())
55
56    def tearDown(self):
57        '''Destroy the GUI'''
58        self.form.close()
59        self.form = None
60
61    def testDefaults(self):
62        '''Test the GUI in its default state'''
[481ff26]63        # Tab widget
[f721030]64        self.assertIsInstance(self.form, QTabWidget)
65        self.assertEqual(self.form.count(), 2)
66
[481ff26]67        # Buttons - data tab
[6fd4e36]68        self.assertEqual(self.form.cmdLoad.text(), "Load data")
[d9150d8]69        self.assertEqual(self.form.cmdDeleteData.text(), "Delete Data")
[f82ab8c]70        self.assertEqual(self.form.cmdDeleteTheory.text(), "Delete")
[481ff26]71        self.assertEqual(self.form.cmdFreeze.text(), "Freeze Theory")
[6fd4e36]72        self.assertEqual(self.form.cmdSendTo.text(), "Send data to")
73        self.assertEqual(self.form.cmdSendTo.iconSize(), QSize(48, 48))
[481ff26]74        self.assertIsInstance(self.form.cmdSendTo.icon(), QIcon)
[f721030]75        self.assertEqual(self.form.chkBatch.text(), "Batch mode")
76        self.assertFalse(self.form.chkBatch.isChecked())
77
[481ff26]78        # Buttons - theory tab
79
80        # Combo boxes
[f721030]81        self.assertEqual(self.form.cbSelect.count(), 6)
[488c49d]82        self.assertEqual(self.form.cbSelect.currentIndex(), 0)
[f721030]83
[481ff26]84        # Models - data
85        self.assertIsInstance(self.form.model, QStandardItemModel)
[f721030]86        self.assertEqual(self.form.treeView.model().rowCount(), 0)
87        self.assertEqual(self.form.treeView.model().columnCount(), 0)
88        self.assertEqual(self.form.model.rowCount(), 0)
89        self.assertEqual(self.form.model.columnCount(), 0)
[481ff26]90        self.assertIsInstance(self.form.data_proxy, QSortFilterProxyModel)
91        self.assertEqual(self.form.data_proxy.sourceModel(), self.form.model)
92        self.assertEqual("[^()]", str(self.form.data_proxy.filterRegExp().pattern()))
93        self.assertIsInstance(self.form.treeView, QTreeView)
94
95        # Models - theory
96        self.assertIsInstance(self.form.theory_model, QStandardItemModel)
97        self.assertEqual(self.form.freezeView.model().rowCount(), 0)
98        self.assertEqual(self.form.freezeView.model().columnCount(), 0)
99        self.assertEqual(self.form.theory_model.rowCount(), 0)
100        self.assertEqual(self.form.theory_model.columnCount(), 0)
101        self.assertIsInstance(self.form.theory_proxy, QSortFilterProxyModel)
102        self.assertEqual(self.form.theory_proxy.sourceModel(), self.form.theory_model)
103        self.assertEqual("[^()]", str(self.form.theory_proxy.filterRegExp().pattern()))
104        self.assertIsInstance(self.form.freezeView, QTreeView)
105
[e540cd2]106    def testWidgets(self):
107        """
108        Test if all required widgets got added
[0cd8612]109        """
[f721030]110    def testLoadButton(self):
111        loadButton = self.form.cmdLoad
112
[9e426c1]113        filename = "cyl_400_20.txt"
114        # Initialize signal spy instances
[f82ab8c]115        spy_file_read = QtSignalSpy(self.form, self.form.communicator.fileReadSignal)
[9e426c1]116
117        # Return no files.
[53c771e]118        QFileDialog.getOpenFileNames = MagicMock(return_value=('',''))
[f721030]119
120        # Click on the Load button
121        QTest.mouseClick(loadButton, Qt.LeftButton)
122
123        # Test the getOpenFileName() dialog called once
[53c771e]124        self.assertTrue(QFileDialog.getOpenFileNames.called)
125        QFileDialog.getOpenFileNames.assert_called_once()
[9e426c1]126
127        # Make sure the signal has not been emitted
[e540cd2]128        self.assertEqual(spy_file_read.count(), 0)
[9e426c1]129
130        # Now, return a single file
[53c771e]131        QFileDialog.getOpenFileNames = MagicMock(return_value=(filename,''))
[e540cd2]132
[9e426c1]133        # Click on the Load button
134        QTest.mouseClick(loadButton, Qt.LeftButton)
[53c771e]135        qApp.processEvents()
[9e426c1]136
137        # Test the getOpenFileName() dialog called once
[53c771e]138        self.assertTrue(QFileDialog.getOpenFileNames.called)
139        QFileDialog.getOpenFileNames.assert_called_once()
[9e426c1]140
141        # Expected one spy instance
[f82ab8c]142        #self.assertEqual(spy_file_read.count(), 1)
143        #self.assertIn(filename, str(spy_file_read.called()[0]['args'][0]))
[f721030]144
[e540cd2]145    def testLoadFiles(self):
146        """
147        Test progress bar update while loading of multiple files
148        """
149        # Set up the spy on progress bar update signal
150        spy_progress_bar_update = QtSignalSpy(self.form,
151            self.form.communicator.progressBarUpdateSignal)
152
153        # Populate the model
[f4a1433]154        filename = ["cyl_400_20.txt", "P123_D2O_10_percent.dat", "cyl_400_20.txt"]
[e540cd2]155        self.form.readData(filename)
156
157        # 0, 0, 33, 66, -1 -> 5 signals reaching progressBar
158        self.assertEqual(spy_progress_bar_update.count(), 5)
159
160        expected_list = [0, 0, 33, 66, -1]
[7fb471d]161        spied_list = [spy_progress_bar_update.called()[i]['args'][0] for i in range(5)]
[e540cd2]162        self.assertEqual(expected_list, spied_list)
163       
[f721030]164    def testDeleteButton(self):
[5032ea68]165        """
166        Functionality of the delete button
167        """
[f82ab8c]168        deleteButton = self.form.cmdDeleteData
[f721030]169
[f82ab8c]170        # Mock the confirmation dialog with return=No
[53c771e]171        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
[f721030]172
173        # Populate the model
[f7d14a1]174        filename = ["cyl_400_20.txt", "cyl_400_20.txt", "cyl_400_20.txt"]
[5032ea68]175        self.form.readData(filename)
[f721030]176
[5032ea68]177        # Assure the model contains three items
178        self.assertEqual(self.form.model.rowCount(), 3)
179
180        # Assure the checkboxes are on
181        item1 = self.form.model.item(0)
182        item2 = self.form.model.item(1)
183        item3 = self.form.model.item(2)
[53c771e]184        self.assertTrue(item1.checkState() == Qt.Checked)
185        self.assertTrue(item2.checkState() == Qt.Checked)
186        self.assertTrue(item3.checkState() == Qt.Checked)
[f721030]187
188        # Click on the delete  button
189        QTest.mouseClick(deleteButton, Qt.LeftButton)
190
191        # Test the warning dialog called once
[53c771e]192        self.assertTrue(QMessageBox.question.called)
[5032ea68]193
194        # Assure the model still contains the items
195        self.assertEqual(self.form.model.rowCount(), 3)
196
197        # Now, mock the confirmation dialog with return=Yes
[53c771e]198        QMessageBox.question = MagicMock(return_value=QMessageBox.Yes)
[5032ea68]199
200        # Click on the delete  button
201        QTest.mouseClick(deleteButton, Qt.LeftButton)
202
203        # Test the warning dialog called once
[53c771e]204        self.assertTrue(QMessageBox.question.called)
[f721030]205
206        # Assure the model contains no items
[5032ea68]207        self.assertEqual(self.form.model.rowCount(), 0)
[f721030]208
[5032ea68]209        # Click delete once again to assure no nasty behaviour on empty model
210        QTest.mouseClick(deleteButton, Qt.LeftButton)
[f721030]211
[481ff26]212    def testDeleteTheory(self):
213        """
214        Test that clicking "Delete" in theories tab removes selected indices
215        """
216        deleteButton = self.form.cmdDeleteTheory
217
218        # Mock the confirmation dialog with return=No
[53c771e]219        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
[481ff26]220
221        # Populate the model
[53c771e]222        item1 = QStandardItem(True)
[481ff26]223        item1.setCheckable(True)
[53c771e]224        item1.setCheckState(Qt.Checked)
[481ff26]225        item1.setText("item 1")
226        self.form.theory_model.appendRow(item1)
[53c771e]227        item2 = QStandardItem(True)
[481ff26]228        item2.setCheckable(True)
[53c771e]229        item2.setCheckState(Qt.Unchecked)
[481ff26]230        item2.setText("item 2")
231        self.form.theory_model.appendRow(item2)
232
233        # Assure the model contains two items
234        self.assertEqual(self.form.theory_model.rowCount(), 2)
235
236        # Assure the checkboxes are on
[53c771e]237        self.assertTrue(item1.checkState() == Qt.Checked)
238        self.assertTrue(item2.checkState() == Qt.Unchecked)
[481ff26]239
240        # Click on the delete  button
241        QTest.mouseClick(deleteButton, Qt.LeftButton)
242
243        # Test the warning dialog called once
[53c771e]244        self.assertTrue(QMessageBox.question.called)
[481ff26]245
246        # Assure the model still contains the items
247        self.assertEqual(self.form.theory_model.rowCount(), 2)
248
249        # Now, mock the confirmation dialog with return=Yes
[53c771e]250        QMessageBox.question = MagicMock(return_value=QMessageBox.Yes)
[481ff26]251
252        # Click on the delete  button
253        QTest.mouseClick(deleteButton, Qt.LeftButton)
254
255        # Test the warning dialog called once
[53c771e]256        self.assertTrue(QMessageBox.question.called)
[481ff26]257
258        # Assure the model contains 1 item
259        self.assertEqual(self.form.theory_model.rowCount(), 1)
260
261        # Set the remaining item to checked
[53c771e]262        self.form.theory_model.item(0).setCheckState(Qt.Checked)
[481ff26]263
264        # Click on the delete button again
265        QTest.mouseClick(deleteButton, Qt.LeftButton)
266
267        # Assure the model contains no items
268        self.assertEqual(self.form.theory_model.rowCount(), 0)
269
270        # Click delete once again to assure no nasty behaviour on empty model
271        QTest.mouseClick(deleteButton, Qt.LeftButton)
272
273
[80468f6]274    def notestSendToButton(self):
[5032ea68]275        """
276        Test that clicking the Send To button sends checked data to a perspective
277        """
[f82ab8c]278        # Send empty data
279        mocked_perspective = self.form.parent.perspective()
280        mocked_perspective.setData = MagicMock()
281
282        # Click on the Send To  button
283        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
284
285        # The set_data method not called
286        self.assertFalse(mocked_perspective.setData.called)
287               
[f721030]288        # Populate the model
[5032ea68]289        filename = ["cyl_400_20.txt"]
290        self.form.readData(filename)
291
[80468f6]292        QApplication.processEvents()
293
[5032ea68]294        # setData is the method we want to see called
[f82ab8c]295        mocked_perspective = self.form.parent.perspective()
296        mocked_perspective.setData = MagicMock(filename)
[f721030]297
298        # Assure the checkbox is on
[5032ea68]299        self.form.cbSelect.setCurrentIndex(0)
[f721030]300
301        # Click on the Send To  button
[5032ea68]302        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
[f721030]303
[80468f6]304        QApplication.processEvents()
305
[f721030]306        # Test the set_data method called once
[80468f6]307        self.assertTrue(mocked_perspective.setData.called)
[5032ea68]308
309        # open another file
310        filename = ["cyl_400_20.txt"]
311        self.form.readData(filename)
312
313        # Mock the warning message
[53c771e]314        QMessageBox = MagicMock()
[5032ea68]315
316        # Click on the button
317        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
318
319        # Assure the message box popped up
[53c771e]320        QMessageBox.assert_called_once()
[f721030]321
[488c49d]322    def testDataSelection(self):
323        """
324        Tests the functionality of the Selection Option combobox
325        """
326        # Populate the model with 1d and 2d data
[f4a1433]327        filename = ["cyl_400_20.txt", "P123_D2O_10_percent.dat"]
[488c49d]328        self.form.readData(filename)
329
[80468f6]330        # Wait a moment for data to load
331        time.sleep(1)
[488c49d]332        # Unselect all data
333        self.form.cbSelect.setCurrentIndex(1)
334
335        # Test the current selection
[5032ea68]336        item1D = self.form.model.item(0)
337        item2D = self.form.model.item(1)
[80468f6]338
[53c771e]339        self.assertTrue(item1D.checkState() == Qt.Unchecked)
340        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
[488c49d]341
342        # Select all data
343        self.form.cbSelect.setCurrentIndex(0)
344
345        # Test the current selection
[53c771e]346        self.assertTrue(item1D.checkState() == Qt.Checked)
347        self.assertTrue(item2D.checkState() == Qt.Checked)       
[488c49d]348
349        # select 1d data
350        self.form.cbSelect.setCurrentIndex(2)
351
352        # Test the current selection
[53c771e]353        self.assertTrue(item1D.checkState() == Qt.Checked)
354        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
[488c49d]355
356        # unselect 1d data
357        self.form.cbSelect.setCurrentIndex(3)
358
359        # Test the current selection
[53c771e]360        self.assertTrue(item1D.checkState() == Qt.Unchecked)
361        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
[488c49d]362
363        # select 2d data
364        self.form.cbSelect.setCurrentIndex(4)
365
366        # Test the current selection
[53c771e]367        self.assertTrue(item1D.checkState() == Qt.Unchecked)
368        self.assertTrue(item2D.checkState() == Qt.Checked)       
[488c49d]369
370        # unselect 2d data
371        self.form.cbSelect.setCurrentIndex(5)
372
373        # Test the current selection
[53c771e]374        self.assertTrue(item1D.checkState() == Qt.Unchecked)
375        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
[488c49d]376
377        # choose impossible index and assure the code raises
378        #with self.assertRaises(Exception):
379        #    self.form.cbSelect.setCurrentIndex(6)
380
[481ff26]381    def testFreezeTheory(self):
382        """
383        Assure theory freeze functionality works
384        """
385        # Not yet tested - agree on design first.
386        pass
387
388    def testRecursivelyCloneItem(self):
389        """
390        Test the rescursive QAbstractItem/QStandardItem clone
391        """
392        # Create an item with several branches
[53c771e]393        item1 = QStandardItem()
394        item2 = QStandardItem()
395        item3 = QStandardItem()
396        item4 = QStandardItem()
397        item5 = QStandardItem()
398        item6 = QStandardItem()
[481ff26]399
400        item4.appendRow(item5)
401        item2.appendRow(item4)
402        item2.appendRow(item6)
403        item1.appendRow(item2)
404        item1.appendRow(item3)
405
406        # Clone
407        new_item = self.form.recursivelyCloneItem(item1)
408
409        # assure the trees look identical
410        self.assertEqual(item1.rowCount(), new_item.rowCount())
411        self.assertEqual(item1.child(0).rowCount(), new_item.child(0).rowCount())
412        self.assertEqual(item1.child(1).rowCount(), new_item.child(1).rowCount())
413        self.assertEqual(item1.child(0).child(0).rowCount(), new_item.child(0).child(0).rowCount())
414
[f721030]415    def testReadData(self):
416        """
[5032ea68]417        Test the low level readData() method
[f721030]418        """
419        filename = ["cyl_400_20.txt"]
420        self.form.manager.add_data = MagicMock()
421
422        # Initialize signal spy instances
[f82ab8c]423        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
424        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
[f721030]425
426        # Read in the file
427        self.form.readData(filename)
428
429        # Expected two status bar updates
[2155824]430        self.assertEqual(spy_status_update.count(), 2)
[f721030]431        self.assertIn(filename[0], str(spy_status_update.called()[0]['args'][0]))
432
433
434        # Check that the model contains the item
435        self.assertEqual(self.form.model.rowCount(), 1)
436        self.assertEqual(self.form.model.columnCount(), 1)
437
438        # The 0th item header should be the name of the file
439        model_item = self.form.model.index(0,0)
[53c771e]440        model_name = self.form.model.data(model_item)
[f721030]441        self.assertEqual(model_name, filename[0])
442
[31c5b58]443    def skip_testDisplayHelp(self): # Skip due to help path change
[481ff26]444        """
445        Test that the Help window gets shown correctly
446        """
[aed0532]447        partial_url = "qtgui/MainWindow/data_explorer_help.html"
[481ff26]448        button1 = self.form.cmdHelp
449        button2 = self.form.cmdHelp_2
450
451        # Click on the Help button
452        QTest.mouseClick(button1, Qt.LeftButton)
[53c771e]453        qApp.processEvents()
[481ff26]454
455        # Check the browser
456        self.assertIn(partial_url, str(self.form._helpView.url()))
457        # Close the browser
458        self.form._helpView.close()
459
460        # Click on the Help_2 button
461        QTest.mouseClick(button2, Qt.LeftButton)
[53c771e]462        qApp.processEvents()
[481ff26]463        # Check the browser
464        self.assertIn(partial_url, str(self.form._helpView.url()))
465
[5032ea68]466    def testLoadFile(self):
467        """
468        Test the threaded call to readData()
469        """
[f82ab8c]470        #self.form.loadFile()
[5032ea68]471        pass
[f721030]472
473    def testGetWList(self):
474        """
[f82ab8c]475        Test the list of known extensions
[f721030]476        """
[481ff26]477        w_list = self.form.getWlist()
478
[f721030]479        defaults = 'All (*.*);;canSAS files (*.xml);;SESANS files' +\
[f4a1433]480            ' (*.ses);;ASCII files (*.txt);;' +\
[f721030]481            'IGOR/DAT 2D Q_map files (*.dat);;IGOR 1D files (*.abs);;'+\
[f4a1433]482            'DANSE files (*.sans)'
[481ff26]483        default_list = defaults.split(';;')
484
[e540cd2]485        for def_format in default_list:
486            self.assertIn(def_format, w_list)
[5032ea68]487       
[f721030]488    def testLoadComplete(self):
489        """
[5032ea68]490        Test the callback method updating the data object
[f721030]491        """
[a281ab8]492        message="Loading Data Complete"
[5032ea68]493        data_dict = {"a1":Data1D()}
[a281ab8]494        output_data = (data_dict, message)
[5032ea68]495
496        self.form.manager.add_data = MagicMock()
497
498        # Initialize signal spy instances
[f82ab8c]499        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
500        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
[f721030]501
[5032ea68]502        # Read in the file
[a281ab8]503        self.form.loadComplete(output_data)
[f721030]504
[5032ea68]505        # "Loading data complete" no longer sent in LoadFile but in callback
506        self.assertIn("Loading Data Complete", str(spy_status_update.called()[0]['args'][0]))
[f721030]507
[5032ea68]508        # Expect one Data Received signal
[f721030]509        self.assertEqual(spy_data_received.count(), 1)
510
[5032ea68]511        # Assure returned dictionary has correct data
512        # We don't know the data ID, so need to iterate over dict
513        data_dict = spy_data_received.called()[0]['args'][0]
[7fb471d]514        for data_key, data_value in data_dict.items():
[5032ea68]515            self.assertIsInstance(data_value, Data1D)
516
517        # Assure add_data on data_manager was called (last call)
518        self.assertTrue(self.form.manager.add_data.called)
519
[80468f6]520    @patch('sas.qtgui.Utilities.GuiUtils.plotsFromCheckedItems')
521    def testNewPlot1D(self, test_patch):
[1042dba]522        """
523        Creating new plots from Data1D/2D
524        """
525        loader = Loader()
526        manager = DataManager()
[8cb6cd6]527        PlotHelper.clear()
528        self.form.enableGraphCombo(None)
529
530        # Make sure the controls are disabled
531        self.assertFalse(self.form.cbgraph.isEnabled())
532        self.assertFalse(self.form.cmdAppend.isEnabled())
[1042dba]533
534        # get Data1D
535        p_file="cyl_400_20.txt"
536        output_object = loader.load(p_file)
[80468f6]537        new_data = [(None, manager.create_gui_data(output_object[0], p_file))]
[1042dba]538
539        # Mask retrieval of the data
[80468f6]540        test_patch.return_value = new_data
[1042dba]541
[8cb6cd6]542        # Mask plotting
543        self.form.parent.workspace = MagicMock()
544
[1042dba]545        # Call the plotting method
546        self.form.newPlot()
547
[80468f6]548        time.sleep(1)
549        QApplication.processEvents()
550
[8cb6cd6]551        # The plot was registered
552        self.assertEqual(len(PlotHelper.currentPlots()), 1)
553
554        self.assertTrue(self.form.cbgraph.isEnabled())
555        self.assertTrue(self.form.cmdAppend.isEnabled())
556
[80468f6]557    @patch('sas.qtgui.Utilities.GuiUtils.plotsFromCheckedItems')
558    def testNewPlot2D(self, test_patch):
[6d05e1d]559        """
560        Creating new plots from Data1D/2D
561        """
562        loader = Loader()
563        manager = DataManager()
564        PlotHelper.clear()
565        self.form.enableGraphCombo(None)
566
567        # Make sure the controls are disabled
568        self.assertFalse(self.form.cbgraph.isEnabled())
569        self.assertFalse(self.form.cmdAppend.isEnabled())
570
571        # get Data2D
[f4a1433]572        p_file="P123_D2O_10_percent.dat"
[6d05e1d]573        output_object = loader.load(p_file)
[80468f6]574        new_data = [(None, manager.create_gui_data(output_object[0], p_file))]
[6d05e1d]575
576        # Mask retrieval of the data
[80468f6]577        test_patch.return_value = new_data
[6d05e1d]578
579        # Mask plotting
580        self.form.parent.workspace = MagicMock()
581
582        # Call the plotting method
583        self.form.newPlot()
584
[80468f6]585        QApplication.processEvents()
586
[6d05e1d]587        # The plot was registered
588        self.assertEqual(len(PlotHelper.currentPlots()), 1)
589
590        self.assertTrue(self.form.cbgraph.isEnabled())
591        self.assertTrue(self.form.cmdAppend.isEnabled())
592
[83eb5208]593    @patch('sas.qtgui.Utilities.GuiUtils.plotsFromCheckedItems')
[31c5b58]594    def testAppendPlot(self, test_patch):
[8cb6cd6]595        """
596        Creating new plots from Data1D/2D
597        """
598        loader = Loader()
599        manager = DataManager()
600
601        PlotHelper.clear()
602        self.form.enableGraphCombo(None)
603
604        # Make sure the controls are disabled
605        self.assertFalse(self.form.cbgraph.isEnabled())
606        self.assertFalse(self.form.cmdAppend.isEnabled())
607
608        # get Data1D
609        p_file="cyl_400_20.txt"
610        output_object = loader.load(p_file)
[53c771e]611        output_item = QStandardItem()
[f4a1433]612        new_data = [(output_item, manager.create_gui_data(output_object[0], p_file))]
[8cb6cd6]613
614        # Mask plotting
615        self.form.parent.workspace = MagicMock()
616
617        # Mask the plot show call
618        Plotter.show = MagicMock()
619
620        # Mask retrieval of the data
[6d05e1d]621        test_patch.return_value = new_data
[8cb6cd6]622
623        # Call the plotting method
624        self.form.newPlot()
625
626        # Call the plotting method again, so we have 2 graphs
627        self.form.newPlot()
628
[80468f6]629        QApplication.processEvents()
[8cb6cd6]630        # See that we have two plots
631        self.assertEqual(len(PlotHelper.currentPlots()), 2)
632
633        # Add data to plot #1
634        self.form.cbgraph.setCurrentIndex(1)
635        self.form.appendPlot()
636
637        # See that we still have two plots
638        self.assertEqual(len(PlotHelper.currentPlots()), 2)
639
640    def testUpdateGraphCombo(self):
641        """
642        Test the combo box update
643        """
644        PlotHelper.clear()
645
[0268aed]646        graph_list=["1","2","3"]
[8cb6cd6]647        self.form.updateGraphCombo(graph_list)
648
649        self.assertEqual(self.form.cbgraph.count(), 3)
[0268aed]650        self.assertEqual(self.form.cbgraph.currentText(), '1')
[8cb6cd6]651
652        graph_list=[]
653        self.form.updateGraphCombo(graph_list)
654        self.assertEqual(self.form.cbgraph.count(), 0)
655
[f82ab8c]656    def testUpdateModelFromPerspective(self):
657        """
658        Assure the model update is correct
659        """
[53c771e]660        good_item = QStandardItem()
[f82ab8c]661        bad_item = "I'm so bad"
662
663        self.form.model.reset = MagicMock()
664
665        self.form.updateModelFromPerspective(good_item)
666
667        # See that the model got reset
[80468f6]668        # self.form.model.reset.assert_called_once()
[f82ab8c]669
670        # See that the bad item causes raise
671        with self.assertRaises(Exception):
672            self.form.updateModelFromPerspective(bad_item)
[5032ea68]673
[28a84e9]674    def testContextMenu(self):
675        """
676        See if the context menu is present
677        """
678        # get Data1D
679        p_file=["cyl_400_20.txt"]
680        # Read in the file
681        output, message = self.form.readData(p_file)
682        self.form.loadComplete((output, message))
683
684        # Pick up the treeview index corresponding to that file
[53c771e]685        index = self.form.treeView.indexAt(QPoint(5,5))
[28a84e9]686        self.form.show()
687
688        # Find out the center pointof the treeView row
689        rect = self.form.treeView.visualRect(index).center()
690
691        self.form.context_menu.exec_ = MagicMock()
692
693        # Move the mouse pointer to the first row
694        QTest.mouseMove(self.form.treeView.viewport(), pos=rect)
695
696        # This doesn't invoke the action/signal. Investigate why?
697        # QTest.mouseClick(self.form.treeView.viewport(), Qt.RightButton, pos=rect)
698
699        # Instead, send the signal directly
700        self.form.treeView.customContextMenuRequested.emit(rect)
701
702        # See that the menu has been shown
703        self.form.context_menu.exec_.assert_called_once()
704
705    def testShowDataInfo(self):
706        """
707        Test of the showDataInfo method
708        """
709        # get Data1D
710        p_file=["cyl_400_20.txt"]
711        # Read in the file
712        output, message = self.form.readData(p_file)
713        self.form.loadComplete((output, message))
714
715        # select the data
716        self.form.treeView.selectAll()
717
718        # Call the tested method
719        self.form.showDataInfo()
720
721        # Test the properties
722        self.assertTrue(self.form.txt_widget.isReadOnly())
723        self.assertEqual(self.form.txt_widget.windowTitle(), "Data Info: cyl_400_20.txt")
724        self.assertIn("Waveln_max", self.form.txt_widget.toPlainText())
725
726        # Slider moved all the way up
727        self.assertEqual(self.form.txt_widget.verticalScrollBar().sliderPosition(), 0)
728
729    def testSaveDataAs(self):
730        """
731        Test the Save As context menu action
732        """
733        # get Data1D
734        p_file=["cyl_400_20.txt"]
735        # Read in the file
736        output, message = self.form.readData(p_file)
737        self.form.loadComplete((output, message))
738
739        # select the data
740        self.form.treeView.selectAll()
741
[80468f6]742        QFileDialog.getSaveFileName = MagicMock(return_value=("cyl_400_20_out", "(*.txt)"))
[28a84e9]743
744        # Call the tested method
745        self.form.saveDataAs()
746        QFileDialog.getSaveFileName.assert_called_with(
747                                caption="Save As",
748                                directory='cyl_400_20_out.txt',
749                                filter='Text files (*.txt);;CanSAS 1D files(*.xml)',
750                                parent=None)
751        QFileDialog.getSaveFileName.assert_called_once()
752
753        # get Data2D
[f4a1433]754        p_file=["P123_D2O_10_percent.dat"]
[28a84e9]755        # Read in the file
756        output, message = self.form.readData(p_file)
757        self.form.loadComplete((output, message))
758
759        # select the data
760        index = self.form.model.index(1, 0)
761        selmodel = self.form.treeView.selectionModel()
762        selmodel.setCurrentIndex(index, QItemSelectionModel.NoUpdate)
763        selmodel.select(index, QItemSelectionModel.Select|QItemSelectionModel.Rows)
764
[80468f6]765        QFileDialog.getSaveFileName = MagicMock(return_value="test.xyz")
[28a84e9]766
767        # Call the tested method
768        self.form.saveDataAs()
769        QFileDialog.getSaveFileName.assert_called_with(
770                                caption="Save As",
[f4a1433]771                                directory='P123_D2O_10_percent_out.dat',
[28a84e9]772                                filter='IGOR/DAT 2D file in Q_map (*.dat)',
773                                parent=None)
774        QFileDialog.getSaveFileName.assert_called_once()
775
[39551a68]776    def testQuickDataPlot(self):
777        """
778        Quick data plot generation.
[cad617b]779        """
780        # get Data1D
781        p_file=["cyl_400_20.txt"]
782        # Read in the file
783        output, message = self.form.readData(p_file)
784        self.form.loadComplete((output, message))
785
786        # select the data
787        self.form.treeView.selectAll()
788
789        Plotter.show = MagicMock() # for masking the display
790
791        self.form.quickDataPlot()
792        self.assertTrue(Plotter.show.called)
793
[80468f6]794    def notestQuickData3DPlot(self):
[cad617b]795        """
796        Slow(er) 3D data plot generation.
797        """
798        # get Data1D
[f4a1433]799        p_file=["P123_D2O_10_percent.dat"]
[cad617b]800        # Read in the file
801        output, message = self.form.readData(p_file)
802        self.form.loadComplete((output, message))
803
804        # select the data
805        self.form.treeView.selectAll()
806
807        Plotter2D.show = MagicMock() # for masking the display
808
809        self.form.quickData3DPlot()
810
811        self.assertTrue(Plotter2D.show.called)
812
813    def testShowEditMask(self):
814        """
815        Edit mask on a 2D plot.
[39551a68]816
817        TODO: add content once plotting finalized
818        """
819        pass
[28a84e9]820
[d9150d8]821    def testDeleteItem(self):
[c6fb57c]822        """
823        Delete selected item from data explorer
824        """
825
826        # Mock the confirmation dialog with return=No
827        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
828
829        # Populate the model
830        filename = ["cyl_400_20.txt", "cyl_400_20.txt", "cyl_400_20.txt"]
831        self.form.readData(filename)
832
833        # Assure the model contains three items
834        self.assertEqual(self.form.model.rowCount(), 3)
835
836        # Add an item to first file item
837        item1 = QtGui.QStandardItem("test")
838        item1.setCheckable(True)
839        self.form.model.item(0).appendRow(item1)
840
841        # Check the new item is in
842
843        self.assertTrue(self.form.model.item(0).hasChildren())
844
845        #select_item = self.form.model.item(0).child(3)
846        select_item = self.form.model.item(0)
847        select_index = self.form.model.indexFromItem(select_item)
848
849        # Open up items
850        self.form.current_view.expandAll()
851
852        # Select the newly created item
853        self.form.current_view.selectionModel().select(select_index, QtCore.QItemSelectionModel.Rows)
854
855        # Attempt at deleting
856        self.form.deleteItem()
857
858        # Test the warning dialog called once
859        self.assertTrue(QMessageBox.question.called)
860
861        # Assure the model still contains the items
862        self.assertEqual(self.form.model.rowCount(), 3)
863
864        # Now, mock the confirmation dialog with return=Yes
865        QMessageBox.question = MagicMock(return_value=QMessageBox.Yes)
866
867        # Select the newly created item
868        self.form.current_view.selectionModel().select(select_index, QtCore.QItemSelectionModel.Rows)
869        # delete it. now for good
870        self.form.deleteItem()
871
872        # Test the warning dialog called once
873        self.assertTrue(QMessageBox.question.called)
874
875        # Assure the model contains no items
876        self.assertEqual(self.form.model.rowCount(), 3)
877
[d9150d8]878    def testClosePlotsForItem(self):
879        """
880        Delete selected item from data explorer should also delete corresponding plots
881        """
882        # Mock the confirmation dialog with return=No
883        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
884
885        loader = Loader()
886        manager = DataManager()
887        PlotHelper.clear()
888        self.form.enableGraphCombo(None)
889
890        # Make sure the controls are disabled
891        self.assertFalse(self.form.cbgraph.isEnabled())
892        self.assertFalse(self.form.cmdAppend.isEnabled())
893
894        # Populate the model
895        filename = ["cyl_400_20.txt"]
896        self.form.readData(filename)
897
898        # Mask plotting
899        self.form.parent.workspace = MagicMock()
900
901        # Call the plotting method
902        self.form.newPlot()
903
904        time.sleep(1)
905        QApplication.processEvents()
906
907        # The plot was registered
908        self.assertEqual(len(PlotHelper.currentPlots()), 1)
909        self.assertEqual(len(self.form.plot_widgets), 1)
910        self.assertEqual(list(self.form.plot_widgets.keys()), ['Graph3'])
911
912        # data index
913        model_item = self.form.model.item(0,0)
914
915        # Call the method
916        self.form.closePlotsForItem(model_item)
917
918        # See that no plot remained
919        self.assertEqual(len(PlotHelper.currentPlots()), 0)
920        self.assertEqual(len(self.form.plot_widgets), 0)
921
[cad617b]922
[f721030]923if __name__ == "__main__":
924    unittest.main()
Note: See TracBrowser for help on using the repository browser.