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
Line 
1import sys
2import time
3import unittest
4
5from PyQt5.QtGui import *
6from PyQt5.QtWidgets import *
7from PyQt5.QtTest import QTest
8from PyQt5.QtCore import *
9from unittest.mock import MagicMock
10from unittest.mock import patch
11from mpl_toolkits.mplot3d import Axes3D
12
13# set up import paths
14import path_prepare
15
16# Local
17from sas.qtgui.Plotting.PlotterData import Data1D
18from sas.sascalc.dataloader.loader import Loader
19from sas.qtgui.MainWindow.DataManager import DataManager
20
21from sas.qtgui.MainWindow.DataExplorer import DataExplorerWindow
22from sas.qtgui.MainWindow.GuiManager import GuiManager
23from sas.qtgui.Utilities.GuiUtils import *
24from UnitTesting.TestUtils import QtSignalSpy
25from sas.qtgui.Plotting.Plotter import Plotter
26from sas.qtgui.Plotting.Plotter2D import Plotter2D
27import sas.qtgui.Plotting.PlotHelper as PlotHelper
28
29if not QApplication.instance():
30    app = QApplication(sys.argv)
31
32class DataExplorerTest(unittest.TestCase):
33    '''Test the Data Explorer GUI'''
34    def setUp(self):
35        '''Create the GUI'''
36        class MyPerspective(object):
37            def communicator(self):
38                return Communicate()
39            def allowBatch(self):
40                return True
41            def setData(self, data_item=None, is_batch=False):
42                return None
43            def title(self):
44                return "Dummy Perspective"
45
46        class dummy_manager(object):
47            def communicator(self):
48                return Communicate()
49            def perspective(self):
50                return MyPerspective()
51            def workspace(self):
52                return None
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'''
63        # Tab widget
64        self.assertIsInstance(self.form, QTabWidget)
65        self.assertEqual(self.form.count(), 2)
66
67        # Buttons - data tab
68        self.assertEqual(self.form.cmdLoad.text(), "Load data")
69        self.assertEqual(self.form.cmdDeleteData.text(), "Delete Data")
70        self.assertEqual(self.form.cmdDeleteTheory.text(), "Delete")
71        self.assertEqual(self.form.cmdFreeze.text(), "Freeze Theory")
72        self.assertEqual(self.form.cmdSendTo.text(), "Send data to")
73        self.assertEqual(self.form.cmdSendTo.iconSize(), QSize(48, 48))
74        self.assertIsInstance(self.form.cmdSendTo.icon(), QIcon)
75        self.assertEqual(self.form.chkBatch.text(), "Batch mode")
76        self.assertFalse(self.form.chkBatch.isChecked())
77
78        # Buttons - theory tab
79
80        # Combo boxes
81        self.assertEqual(self.form.cbSelect.count(), 6)
82        self.assertEqual(self.form.cbSelect.currentIndex(), 0)
83
84        # Models - data
85        self.assertIsInstance(self.form.model, QStandardItemModel)
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)
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
106    def testWidgets(self):
107        """
108        Test if all required widgets got added
109        """
110    def testLoadButton(self):
111        loadButton = self.form.cmdLoad
112
113        filename = "cyl_400_20.txt"
114        # Initialize signal spy instances
115        spy_file_read = QtSignalSpy(self.form, self.form.communicator.fileReadSignal)
116
117        # Return no files.
118        QFileDialog.getOpenFileNames = MagicMock(return_value=('',''))
119
120        # Click on the Load button
121        QTest.mouseClick(loadButton, Qt.LeftButton)
122
123        # Test the getOpenFileName() dialog called once
124        self.assertTrue(QFileDialog.getOpenFileNames.called)
125        QFileDialog.getOpenFileNames.assert_called_once()
126
127        # Make sure the signal has not been emitted
128        self.assertEqual(spy_file_read.count(), 0)
129
130        # Now, return a single file
131        QFileDialog.getOpenFileNames = MagicMock(return_value=(filename,''))
132
133        # Click on the Load button
134        QTest.mouseClick(loadButton, Qt.LeftButton)
135        qApp.processEvents()
136
137        # Test the getOpenFileName() dialog called once
138        self.assertTrue(QFileDialog.getOpenFileNames.called)
139        QFileDialog.getOpenFileNames.assert_called_once()
140
141        # Expected one spy instance
142        #self.assertEqual(spy_file_read.count(), 1)
143        #self.assertIn(filename, str(spy_file_read.called()[0]['args'][0]))
144
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
154        filename = ["cyl_400_20.txt", "P123_D2O_10_percent.dat", "cyl_400_20.txt"]
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]
161        spied_list = [spy_progress_bar_update.called()[i]['args'][0] for i in range(5)]
162        self.assertEqual(expected_list, spied_list)
163       
164    def testDeleteButton(self):
165        """
166        Functionality of the delete button
167        """
168        deleteButton = self.form.cmdDeleteData
169
170        # Mock the confirmation dialog with return=No
171        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
172
173        # Populate the model
174        filename = ["cyl_400_20.txt", "cyl_400_20.txt", "cyl_400_20.txt"]
175        self.form.readData(filename)
176
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)
184        self.assertTrue(item1.checkState() == Qt.Checked)
185        self.assertTrue(item2.checkState() == Qt.Checked)
186        self.assertTrue(item3.checkState() == Qt.Checked)
187
188        # Click on the delete  button
189        QTest.mouseClick(deleteButton, Qt.LeftButton)
190
191        # Test the warning dialog called once
192        self.assertTrue(QMessageBox.question.called)
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
198        QMessageBox.question = MagicMock(return_value=QMessageBox.Yes)
199
200        # Click on the delete  button
201        QTest.mouseClick(deleteButton, Qt.LeftButton)
202
203        # Test the warning dialog called once
204        self.assertTrue(QMessageBox.question.called)
205
206        # Assure the model contains no items
207        self.assertEqual(self.form.model.rowCount(), 0)
208
209        # Click delete once again to assure no nasty behaviour on empty model
210        QTest.mouseClick(deleteButton, Qt.LeftButton)
211
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
219        QMessageBox.question = MagicMock(return_value=QMessageBox.No)
220
221        # Populate the model
222        item1 = QStandardItem(True)
223        item1.setCheckable(True)
224        item1.setCheckState(Qt.Checked)
225        item1.setText("item 1")
226        self.form.theory_model.appendRow(item1)
227        item2 = QStandardItem(True)
228        item2.setCheckable(True)
229        item2.setCheckState(Qt.Unchecked)
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
237        self.assertTrue(item1.checkState() == Qt.Checked)
238        self.assertTrue(item2.checkState() == Qt.Unchecked)
239
240        # Click on the delete  button
241        QTest.mouseClick(deleteButton, Qt.LeftButton)
242
243        # Test the warning dialog called once
244        self.assertTrue(QMessageBox.question.called)
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
250        QMessageBox.question = MagicMock(return_value=QMessageBox.Yes)
251
252        # Click on the delete  button
253        QTest.mouseClick(deleteButton, Qt.LeftButton)
254
255        # Test the warning dialog called once
256        self.assertTrue(QMessageBox.question.called)
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
262        self.form.theory_model.item(0).setCheckState(Qt.Checked)
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
274    def notestSendToButton(self):
275        """
276        Test that clicking the Send To button sends checked data to a perspective
277        """
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               
288        # Populate the model
289        filename = ["cyl_400_20.txt"]
290        self.form.readData(filename)
291
292        QApplication.processEvents()
293
294        # setData is the method we want to see called
295        mocked_perspective = self.form.parent.perspective()
296        mocked_perspective.setData = MagicMock(filename)
297
298        # Assure the checkbox is on
299        self.form.cbSelect.setCurrentIndex(0)
300
301        # Click on the Send To  button
302        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
303
304        QApplication.processEvents()
305
306        # Test the set_data method called once
307        self.assertTrue(mocked_perspective.setData.called)
308
309        # open another file
310        filename = ["cyl_400_20.txt"]
311        self.form.readData(filename)
312
313        # Mock the warning message
314        QMessageBox = MagicMock()
315
316        # Click on the button
317        QTest.mouseClick(self.form.cmdSendTo, Qt.LeftButton)
318
319        # Assure the message box popped up
320        QMessageBox.assert_called_once()
321
322    def testDataSelection(self):
323        """
324        Tests the functionality of the Selection Option combobox
325        """
326        # Populate the model with 1d and 2d data
327        filename = ["cyl_400_20.txt", "P123_D2O_10_percent.dat"]
328        self.form.readData(filename)
329
330        # Wait a moment for data to load
331        time.sleep(1)
332        # Unselect all data
333        self.form.cbSelect.setCurrentIndex(1)
334
335        # Test the current selection
336        item1D = self.form.model.item(0)
337        item2D = self.form.model.item(1)
338
339        self.assertTrue(item1D.checkState() == Qt.Unchecked)
340        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
341
342        # Select all data
343        self.form.cbSelect.setCurrentIndex(0)
344
345        # Test the current selection
346        self.assertTrue(item1D.checkState() == Qt.Checked)
347        self.assertTrue(item2D.checkState() == Qt.Checked)       
348
349        # select 1d data
350        self.form.cbSelect.setCurrentIndex(2)
351
352        # Test the current selection
353        self.assertTrue(item1D.checkState() == Qt.Checked)
354        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
355
356        # unselect 1d data
357        self.form.cbSelect.setCurrentIndex(3)
358
359        # Test the current selection
360        self.assertTrue(item1D.checkState() == Qt.Unchecked)
361        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
362
363        # select 2d data
364        self.form.cbSelect.setCurrentIndex(4)
365
366        # Test the current selection
367        self.assertTrue(item1D.checkState() == Qt.Unchecked)
368        self.assertTrue(item2D.checkState() == Qt.Checked)       
369
370        # unselect 2d data
371        self.form.cbSelect.setCurrentIndex(5)
372
373        # Test the current selection
374        self.assertTrue(item1D.checkState() == Qt.Unchecked)
375        self.assertTrue(item2D.checkState() == Qt.Unchecked)       
376
377        # choose impossible index and assure the code raises
378        #with self.assertRaises(Exception):
379        #    self.form.cbSelect.setCurrentIndex(6)
380
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
393        item1 = QStandardItem()
394        item2 = QStandardItem()
395        item3 = QStandardItem()
396        item4 = QStandardItem()
397        item5 = QStandardItem()
398        item6 = QStandardItem()
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
415    def testReadData(self):
416        """
417        Test the low level readData() method
418        """
419        filename = ["cyl_400_20.txt"]
420        self.form.manager.add_data = MagicMock()
421
422        # Initialize signal spy instances
423        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
424        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
425
426        # Read in the file
427        self.form.readData(filename)
428
429        # Expected two status bar updates
430        self.assertEqual(spy_status_update.count(), 2)
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)
440        model_name = self.form.model.data(model_item)
441        self.assertEqual(model_name, filename[0])
442
443    def skip_testDisplayHelp(self): # Skip due to help path change
444        """
445        Test that the Help window gets shown correctly
446        """
447        partial_url = "qtgui/MainWindow/data_explorer_help.html"
448        button1 = self.form.cmdHelp
449        button2 = self.form.cmdHelp_2
450
451        # Click on the Help button
452        QTest.mouseClick(button1, Qt.LeftButton)
453        qApp.processEvents()
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)
462        qApp.processEvents()
463        # Check the browser
464        self.assertIn(partial_url, str(self.form._helpView.url()))
465
466    def testLoadFile(self):
467        """
468        Test the threaded call to readData()
469        """
470        #self.form.loadFile()
471        pass
472
473    def testGetWList(self):
474        """
475        Test the list of known extensions
476        """
477        w_list = self.form.getWlist()
478
479        defaults = 'All (*.*);;canSAS files (*.xml);;SESANS files' +\
480            ' (*.ses);;ASCII files (*.txt);;' +\
481            'IGOR/DAT 2D Q_map files (*.dat);;IGOR 1D files (*.abs);;'+\
482            'DANSE files (*.sans)'
483        default_list = defaults.split(';;')
484
485        for def_format in default_list:
486            self.assertIn(def_format, w_list)
487       
488    def testLoadComplete(self):
489        """
490        Test the callback method updating the data object
491        """
492        message="Loading Data Complete"
493        data_dict = {"a1":Data1D()}
494        output_data = (data_dict, message)
495
496        self.form.manager.add_data = MagicMock()
497
498        # Initialize signal spy instances
499        spy_status_update = QtSignalSpy(self.form, self.form.communicator.statusBarUpdateSignal)
500        spy_data_received = QtSignalSpy(self.form, self.form.communicator.fileDataReceivedSignal)
501
502        # Read in the file
503        self.form.loadComplete(output_data)
504
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]))
507
508        # Expect one Data Received signal
509        self.assertEqual(spy_data_received.count(), 1)
510
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]
514        for data_key, data_value in data_dict.items():
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
520    @patch('sas.qtgui.Utilities.GuiUtils.plotsFromCheckedItems')
521    def testNewPlot1D(self, test_patch):
522        """
523        Creating new plots from Data1D/2D
524        """
525        loader = Loader()
526        manager = DataManager()
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())
533
534        # get Data1D
535        p_file="cyl_400_20.txt"
536        output_object = loader.load(p_file)
537        new_data = [(None, manager.create_gui_data(output_object[0], p_file))]
538
539        # Mask retrieval of the data
540        test_patch.return_value = new_data
541
542        # Mask plotting
543        self.form.parent.workspace = MagicMock()
544
545        # Call the plotting method
546        self.form.newPlot()
547
548        time.sleep(1)
549        QApplication.processEvents()
550
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
557    @patch('sas.qtgui.Utilities.GuiUtils.plotsFromCheckedItems')
558    def testNewPlot2D(self, test_patch):
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
572        p_file="P123_D2O_10_percent.dat"
573        output_object = loader.load(p_file)
574        new_data = [(None, manager.create_gui_data(output_object[0], p_file))]
575
576        # Mask retrieval of the data
577        test_patch.return_value = new_data
578
579        # Mask plotting
580        self.form.parent.workspace = MagicMock()
581
582        # Call the plotting method
583        self.form.newPlot()
584
585        QApplication.processEvents()
586
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
593    @patch('sas.qtgui.Utilities.GuiUtils.plotsFromCheckedItems')
594    def testAppendPlot(self, test_patch):
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)
611        output_item = QStandardItem()
612        new_data = [(output_item, manager.create_gui_data(output_object[0], p_file))]
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
621        test_patch.return_value = new_data
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
629        QApplication.processEvents()
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
646        graph_list=["1","2","3"]
647        self.form.updateGraphCombo(graph_list)
648
649        self.assertEqual(self.form.cbgraph.count(), 3)
650        self.assertEqual(self.form.cbgraph.currentText(), '1')
651
652        graph_list=[]
653        self.form.updateGraphCombo(graph_list)
654        self.assertEqual(self.form.cbgraph.count(), 0)
655
656    def testUpdateModelFromPerspective(self):
657        """
658        Assure the model update is correct
659        """
660        good_item = QStandardItem()
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
668        # self.form.model.reset.assert_called_once()
669
670        # See that the bad item causes raise
671        with self.assertRaises(Exception):
672            self.form.updateModelFromPerspective(bad_item)
673
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
685        index = self.form.treeView.indexAt(QPoint(5,5))
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
742        QFileDialog.getSaveFileName = MagicMock(return_value=("cyl_400_20_out", "(*.txt)"))
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
754        p_file=["P123_D2O_10_percent.dat"]
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
765        QFileDialog.getSaveFileName = MagicMock(return_value="test.xyz")
766
767        # Call the tested method
768        self.form.saveDataAs()
769        QFileDialog.getSaveFileName.assert_called_with(
770                                caption="Save As",
771                                directory='P123_D2O_10_percent_out.dat',
772                                filter='IGOR/DAT 2D file in Q_map (*.dat)',
773                                parent=None)
774        QFileDialog.getSaveFileName.assert_called_once()
775
776    def testQuickDataPlot(self):
777        """
778        Quick data plot generation.
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
794    def notestQuickData3DPlot(self):
795        """
796        Slow(er) 3D data plot generation.
797        """
798        # get Data1D
799        p_file=["P123_D2O_10_percent.dat"]
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.
816
817        TODO: add content once plotting finalized
818        """
819        pass
820
821    def testDeleteItem(self):
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
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
922
923if __name__ == "__main__":
924    unittest.main()
Note: See TracBrowser for help on using the repository browser.