source: sasview/src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py @ cadd595a

Last change on this file since cadd595a was c7358b2, checked in by wojciech, 7 years ago

Tooltips tests added

  • Property mode set to 100644
File size: 35.1 KB
Line 
1import sys
2import unittest
3import time
4
5from PyQt4 import QtGui
6from PyQt4 import QtTest
7from PyQt4 import QtCore
8from mock import MagicMock
9from twisted.internet import threads
10
11# set up import paths
12import sas.qtgui.path_prepare
13
14# Local
15from sas.qtgui.Utilities.GuiUtils import *
16from sas.qtgui.Perspectives.Fitting.FittingWidget import *
17from sas.qtgui.UnitTesting.TestUtils import QtSignalSpy
18
19from sas.qtgui.Plotting.PlotterData import Data1D
20from sas.qtgui.Plotting.PlotterData import Data2D
21
22if not QtGui.QApplication.instance():
23    app = QtGui.QApplication(sys.argv)
24
25class dummy_manager(object):
26    HELP_DIRECTORY_LOCATION = "html"
27    communicate = Communicate()
28
29class FittingWidgetTest(unittest.TestCase):
30    """Test the fitting widget GUI"""
31
32    def setUp(self):
33        """Create the GUI"""
34        self.widget = FittingWidget(dummy_manager())
35
36    def tearDown(self):
37        """Destroy the GUI"""
38        self.widget.close()
39        del self.widget
40
41    def testDefaults(self):
42        """Test the GUI in its default state"""
43        self.assertIsInstance(self.widget, QtGui.QWidget)
44        self.assertEqual(self.widget.windowTitle(), "Fitting")
45        self.assertEqual(self.widget.sizePolicy().Policy(), QtGui.QSizePolicy.Fixed)
46        self.assertIsInstance(self.widget.lstParams.model(), QtGui.QStandardItemModel)
47        self.assertIsInstance(self.widget.lstPoly.model(), QtGui.QStandardItemModel)
48        self.assertIsInstance(self.widget.lstMagnetic.model(), QtGui.QStandardItemModel)
49        self.assertFalse(self.widget.cbModel.isEnabled())
50        self.assertFalse(self.widget.cbStructureFactor.isEnabled())
51        self.assertFalse(self.widget.cmdFit.isEnabled())
52        self.assertTrue(self.widget.acceptsData())
53        self.assertFalse(self.widget.data_is_loaded)
54
55    def testSelectCategoryDefault(self):
56        """
57        Test if model categories have been loaded properly
58        """
59        fittingWindow =  self.widget
60
61        #Test loading from json categories
62        category_list = fittingWindow.master_category_dict.keys()
63
64        for category in category_list:
65            self.assertNotEqual(fittingWindow.cbCategory.findText(category),-1)
66
67        #Test what is current text in the combobox
68        self.assertEqual(fittingWindow.cbCategory.currentText(), CATEGORY_DEFAULT)
69
70    def testWidgetWithData(self):
71        """
72        Test the instantiation of the widget with initial data
73        """
74        data = Data1D(x=[1,2], y=[1,2])
75        GuiUtils.dataFromItem = MagicMock(return_value=data)
76        item = QtGui.QStandardItem("test")
77
78        widget_with_data = FittingWidget(dummy_manager(), data=item, tab_id=3)
79
80        self.assertEqual(widget_with_data.data, data)
81        self.assertTrue(widget_with_data.data_is_loaded)
82        # self.assertTrue(widget_with_data.cmdFit.isEnabled())
83        self.assertFalse(widget_with_data.acceptsData())
84
85    def testSelectPolydispersity(self):
86        """
87        Test if models have been loaded properly
88        """
89        fittingWindow =  self.widget
90
91        self.assertIsInstance(fittingWindow.lstPoly.itemDelegate(), QtGui.QStyledItemDelegate)
92        #Test loading from json categories
93        fittingWindow.SASModelToQModel("cylinder")
94        pd_index = fittingWindow.lstPoly.model().index(0,0)
95        self.assertEqual(str(pd_index.data().toString()), "Distribution of radius")
96        pd_index = fittingWindow.lstPoly.model().index(1,0)
97        self.assertEqual(str(pd_index.data().toString()), "Distribution of length")
98
99        # test the delegate a bit
100        delegate = fittingWindow.lstPoly.itemDelegate()
101        self.assertEqual(len(delegate.POLYDISPERSE_FUNCTIONS), 5)
102        self.assertEqual(delegate.editableParameters(), [2, 3, 4, 5])
103        self.assertEqual(delegate.poly_function, 6)
104        self.assertIsInstance(delegate.combo_updated, QtCore.pyqtBoundSignal)
105
106    def testSelectStructureFactor(self):
107        """
108        Test if structure factors have been loaded properly
109        """
110        fittingWindow =  self.widget
111
112        #Test for existence in combobox
113        self.assertNotEqual(fittingWindow.cbStructureFactor.findText("stickyhardsphere"),-1)
114        self.assertNotEqual(fittingWindow.cbStructureFactor.findText("hayter_msa"),-1)
115        self.assertNotEqual(fittingWindow.cbStructureFactor.findText("squarewell"),-1)
116        self.assertNotEqual(fittingWindow.cbStructureFactor.findText("hardsphere"),-1)
117
118        #Test what is current text in the combobox
119        self.assertTrue(fittingWindow.cbCategory.currentText(), "None")
120
121    def testSignals(self):
122        """
123        Test the widget emitted signals
124        """
125        pass
126
127    def testSelectCategory(self):
128        """
129        Assure proper behaviour on changing category
130        """
131        self.widget.show()
132        self.assertEqual(self.widget._previous_category_index, 0)
133        # confirm the model combo contains no models
134        self.assertEqual(self.widget.cbModel.count(), 0)
135
136        # invoke the method by changing the index
137        category_index = self.widget.cbCategory.findText("Shape Independent")
138        self.widget.cbCategory.setCurrentIndex(category_index)
139
140        # test the model combo content
141        self.assertEqual(self.widget.cbModel.count(), 29)
142
143        # Try to change back to default
144        self.widget.cbCategory.setCurrentIndex(0)
145
146        # Observe no such luck
147        self.assertEqual(self.widget.cbCategory.currentIndex(), 6)
148        self.assertEqual(self.widget.cbModel.count(), 29)
149
150        # Set the structure factor
151        structure_index=self.widget.cbCategory.findText(CATEGORY_STRUCTURE)
152        self.widget.cbCategory.setCurrentIndex(structure_index)
153        # check the enablement of controls
154        self.assertFalse(self.widget.cbModel.isEnabled())
155        self.assertTrue(self.widget.cbStructureFactor.isEnabled())
156
157    def testSelectModel(self):
158        """
159        Assure proper behaviour on changing model
160        """
161        self.widget.show()
162        # Change the category index so we have some models
163        category_index = self.widget.cbCategory.findText("Shape Independent")
164        self.widget.cbCategory.setCurrentIndex(category_index)
165
166        # check the enablement of controls
167        self.assertTrue(self.widget.cbModel.isEnabled())
168        self.assertFalse(self.widget.cbStructureFactor.isEnabled())
169
170        # set up the model update spy
171        # spy = QtSignalSpy(self.widget._model_model, self.widget._model_model.itemChanged)
172
173        # mock the tested methods
174        self.widget.SASModelToQModel = MagicMock()
175        self.widget.createDefaultDataset = MagicMock()
176        self.widget.calculateQGridForModel = MagicMock()
177        #
178        # Now change the model
179        self.widget.cbModel.setCurrentIndex(3)
180        self.assertEqual(self.widget.cbModel.currentText(),'dab')
181
182        # No data sent -> no index set, only createDefaultDataset called
183        self.assertTrue(self.widget.createDefaultDataset.called)
184        self.assertTrue(self.widget.SASModelToQModel.called)
185        self.assertFalse(self.widget.calculateQGridForModel.called)
186
187        # Let's tell the widget that data has been loaded
188        self.widget.data_is_loaded = True
189        # Reset the sasmodel index
190        self.widget.cbModel.setCurrentIndex(1)
191        self.assertEqual(self.widget.cbModel.currentText(),'broad_peak')
192
193        # Observe calculateQGridForModel called
194        self.assertTrue(self.widget.calculateQGridForModel.called)
195
196    def testSelectFactor(self):
197        """
198        Assure proper behaviour on changing structure factor
199        """
200        self.widget.show()
201        # Change the category index so we have some models
202        category_index = self.widget.cbCategory.findText("Shape Independent")
203        self.widget.cbCategory.setCurrentIndex(category_index)
204        # Change the model to one that supports structure factors
205        model_index = self.widget.cbModel.findText('fractal_core_shell')
206        self.widget.cbModel.setCurrentIndex(model_index)
207
208        # Check that the factor combo is active and the default is chosen
209        self.assertTrue(self.widget.cbStructureFactor.isEnabled())
210        self.assertEqual(self.widget.cbStructureFactor.currentText(), STRUCTURE_DEFAULT)
211
212        # We have this many rows in the model
213        rowcount = self.widget._model_model.rowCount()
214        #self.assertEqual(self.widget._model_model.rowCount(), 8)
215
216        # Change structure factor to something more exciting
217        structure_index = self.widget.cbStructureFactor.findText('squarewell')
218        self.widget.cbStructureFactor.setCurrentIndex(structure_index)
219
220        # We have 4 more rows now
221        self.assertEqual(self.widget._model_model.rowCount(), rowcount+4)
222
223        # Switch models
224        self.widget.cbModel.setCurrentIndex(0)
225
226        # Observe factor reset to None
227        self.assertEqual(self.widget.cbStructureFactor.currentText(), STRUCTURE_DEFAULT)
228
229        # Switch category to structure factor
230        structure_index=self.widget.cbCategory.findText(CATEGORY_STRUCTURE)
231        self.widget.cbCategory.setCurrentIndex(structure_index)
232        # Observe the correct enablement
233        self.assertTrue(self.widget.cbStructureFactor.isEnabled())
234        self.assertFalse(self.widget.cbModel.isEnabled())
235        self.assertEqual(self.widget._model_model.rowCount(), 0)
236
237        # Choose the last factor
238        last_index = self.widget.cbStructureFactor.count()
239        self.widget.cbStructureFactor.setCurrentIndex(last_index-1)
240        # Do we have all the rows?
241        self.assertEqual(self.widget._model_model.rowCount(), 4)
242
243        # Are the command buttons properly enabled?
244        self.assertTrue(self.widget.cmdPlot.isEnabled())
245        self.assertFalse(self.widget.cmdFit.isEnabled())
246
247    def testReadCategoryInfo(self):
248        """
249        Check the category file reader
250        """
251        # Tested in default checks
252        pass
253
254    def testUpdateParamsFromModel(self):
255        """
256        Checks the sasmodel parameter update from QModel items
257        """
258        # Tested in default checks
259        pass
260
261    def testCreateTheoryIndex(self):
262        """
263        Test the data->QIndex conversion
264        """
265        # set up the model update spy
266        spy = QtSignalSpy(self.widget._model_model, self.widget.communicate.updateTheoryFromPerspectiveSignal)
267
268        self.widget.show()
269        # Change the category index so we have some models
270        self.widget.cbCategory.setCurrentIndex(1)
271
272        # Create the index
273        self.widget.createTheoryIndex(Data1D(x=[1,2], y=[1,2]))
274
275        # Make sure the signal has been emitted
276        self.assertEqual(spy.count(), 1)
277
278        # Check the argument type
279        self.assertIsInstance(spy.called()[0]['args'][0], QtGui.QStandardItem)
280
281    def testCalculateQGridForModel(self):
282        """
283        Check that the fitting 1D data object is ready
284        """
285        # Mock the thread creation
286        threads.deferToThread = MagicMock()
287        # Model for theory
288        self.widget.SASModelToQModel("cylinder")
289        # Call the tested method
290        self.widget.calculateQGridForModel()
291        time.sleep(1)
292        # Test the mock
293        self.assertTrue(threads.deferToThread.called)
294        self.assertEqual(threads.deferToThread.call_args_list[0][0][0].__name__, "compute")
295
296    def testCalculateResiduals(self):
297        """
298        Check that the residuals are calculated and plots updated
299        """
300        test_data = Data1D(x=[1,2], y=[1,2])
301
302        # Model for theory
303        self.widget.SASModelToQModel("cylinder")
304        # Invoke the tested method
305        self.widget.calculateResiduals(test_data)
306        # Check the Chi2 value - should be undetermined
307        self.assertEqual(self.widget.lblChi2Value.text(), '---')
308
309        # Force same data into logic
310        self.widget.logic.data = test_data
311        self.widget.calculateResiduals(test_data)
312        # Now, the difference is 0, as data is the same
313        self.assertEqual(self.widget.lblChi2Value.text(), '0')
314
315        # Change data
316        test_data_2 = Data1D(x=[1,2], y=[2.1,3.49])
317        self.widget.logic.data = test_data_2
318        self.widget.calculateResiduals(test_data)
319        # Now, the difference is non-zero
320        self.assertEqual(float(self.widget.lblChi2Value.text()), 1.7151)
321
322    def testSetPolyModel(self):
323        """
324        Test the polydispersity model setup
325        """
326        self.widget.show()
327        # Change the category index so we have a model with no poly
328        category_index = self.widget.cbCategory.findText("Shape Independent")
329        self.widget.cbCategory.setCurrentIndex(category_index)
330        # Check the poly model
331        self.assertEqual(self.widget._poly_model.rowCount(), 0)
332        self.assertEqual(self.widget._poly_model.columnCount(), 0)
333
334        # Change the category index so we have a model available
335        self.widget.cbCategory.setCurrentIndex(2)
336
337        # Check the poly model
338        self.assertEqual(self.widget._poly_model.rowCount(), 4)
339        self.assertEqual(self.widget._poly_model.columnCount(), 8)
340
341        # Test the header
342        self.assertEqual(self.widget.lstPoly.horizontalHeader().count(), 8)
343        self.assertFalse(self.widget.lstPoly.horizontalHeader().stretchLastSection())
344
345        # Test tooltips
346        self.assertEqual(len(self.widget._poly_model.header_tooltips), 8)
347
348        header_tooltips = ['Select parameter for fitting',
349                             'Enter polydispersity ratio (STD/mean). '
350                             'STD: standard deviation from the mean value',
351                             'Enter minimum value for parameter',
352                             'Enter maximum value for parameter',
353                             'Enter number of points for parameter',
354                             'Enter number of sigmas parameter',
355                             'Select distribution function',
356                             'Select filename with user-definable distribution']
357        for column, tooltip in enumerate(header_tooltips):
358             self.assertEqual(self.widget._poly_model.headerData( column,
359                QtCore.Qt.Horizontal, QtCore.Qt.ToolTipRole),
360                         header_tooltips[column])
361
362        # Test presence of comboboxes in last column
363        for row in xrange(self.widget._poly_model.rowCount()):
364            func_index = self.widget._poly_model.index(row, 6)
365            self.assertTrue(isinstance(self.widget.lstPoly.indexWidget(func_index), QtGui.QComboBox))
366            self.assertIn('Distribution of', self.widget._poly_model.item(row, 0).text())
367        #self.widget.close()
368
369    def testPolyModelChange(self):
370        """
371        Polydispersity model changed - test all possible scenarios
372        """
373        self.widget.show()
374        # Change the category index so we have a model with polydisp
375        category_index = self.widget.cbCategory.findText("Cylinder")
376        self.widget.cbCategory.setCurrentIndex(category_index)
377
378        # click on a poly parameter checkbox
379        index = self.widget._poly_model.index(0,0)
380        # Set the checbox
381        self.widget._poly_model.item(0,0).setCheckState(2)
382        # Assure the parameter is added
383        self.assertEqual(self.widget.parameters_to_fit, ['radius_bell.width'])
384
385        # Add another parameter
386        self.widget._poly_model.item(2,0).setCheckState(2)
387        # Assure the parameters are added
388        self.assertEqual(self.widget.parameters_to_fit, ['radius_bell.width', 'length.width'])
389
390        # Change the min/max values
391        self.assertEqual(self.widget.kernel_module.details['radius_bell'][1], 0.0)
392        self.widget._poly_model.item(0,2).setText("1.0")
393        self.assertEqual(self.widget.kernel_module.details['radius_bell'][1], 1.0)
394
395        # Change the number of points
396        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35)
397        self.widget._poly_model.item(0,4).setText("22")
398        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22)
399        # try something stupid
400        self.widget._poly_model.item(0,4).setText("butt")
401        # see that this didn't annoy the control at all
402        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22)
403
404        # Change the number of sigmas
405        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 3)
406        self.widget._poly_model.item(0,5).setText("222")
407        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222)
408        # try something stupid again
409        self.widget._poly_model.item(0,4).setText("beer")
410        # no efect
411        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222)
412
413    def testOnPolyComboIndexChange(self):
414        """
415        Test the slot method for polydisp. combo box index change
416        """
417        self.widget.show()
418        # Change the category index so we have a model with polydisp
419        category_index = self.widget.cbCategory.findText("Cylinder")
420        self.widget.cbCategory.setCurrentIndex(category_index)
421
422        # call method with default settings
423        self.widget.onPolyComboIndexChange('gaussian', 0)
424        # check values
425        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35)
426        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 3)
427        # Change the index
428        self.widget.onPolyComboIndexChange('rectangle', 0)
429        # check values
430        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35)
431        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 1.70325)
432        # Change the index
433        self.widget.onPolyComboIndexChange('lognormal', 0)
434        # check values
435        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80)
436        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8)
437        # Change the index
438        self.widget.onPolyComboIndexChange('schulz', 0)
439        # check values
440        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80)
441        self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8)
442
443        # mock up file load
444        self.widget.loadPolydispArray = MagicMock()
445        # Change to 'array'
446        self.widget.onPolyComboIndexChange('array', 0)
447        # See the mock fire
448        self.assertTrue(self.widget.loadPolydispArray.called)
449
450    def testLoadPolydispArray(self):
451        """
452        Test opening of the load file dialog for 'array' polydisp. function
453        """
454        filename = os.path.join("UnitTesting", "testdata_noexist.txt")
455        QtGui.QFileDialog.getOpenFileName = MagicMock(return_value=filename)
456        self.widget.show()
457        # Change the category index so we have a model with polydisp
458        category_index = self.widget.cbCategory.findText("Cylinder")
459        self.widget.cbCategory.setCurrentIndex(category_index)
460
461        self.widget.onPolyComboIndexChange('array', 0)
462        # check values - unchanged since the file doesn't exist
463        self.assertTrue(self.widget._poly_model.item(0, 1).isEnabled())
464        with self.assertRaises(AttributeError):
465            self.widget.disp_model()
466
467        # good file
468        filename = os.path.join("UnitTesting", "testdata.txt")
469        QtGui.QFileDialog.getOpenFileName = MagicMock(return_value=filename)
470
471        self.widget.onPolyComboIndexChange('array', 0)
472        # check values - disabled control, present weights
473        self.assertFalse(self.widget._poly_model.item(0, 1).isEnabled())
474        self.assertEqual(self.widget.disp_model.weights[0], 2.83954)
475        self.assertEqual(len(self.widget.disp_model.weights), 19)
476        self.assertEqual(len(self.widget.disp_model.values), 19)
477        self.assertEqual(self.widget.disp_model.values[0], 0.0)
478        self.assertEqual(self.widget.disp_model.values[18], 3.67347)
479
480    def testSetMagneticModel(self):
481        """
482        Test the magnetic model setup
483        """
484        self.widget.show()
485        # Change the category index so we have a model available
486        category_index = self.widget.cbCategory.findText("Sphere")
487        self.widget.cbCategory.setCurrentIndex(category_index)
488
489        # Check the magnetic model
490        self.assertEqual(self.widget._magnet_model.rowCount(), 9)
491        self.assertEqual(self.widget._magnet_model.columnCount(), 5)
492
493        # Test the header
494        self.assertEqual(self.widget.lstMagnetic.horizontalHeader().count(), 5)
495        self.assertFalse(self.widget.lstMagnetic.horizontalHeader().stretchLastSection())
496
497        #Test tooltips
498        self.assertEqual(len(self.widget._magnet_model.header_tooltips), 5)
499
500        header_tooltips = ['Select parameter for fitting',
501                             'Enter parameter value',
502                             'Enter minimum value for parameter',
503                             'Enter maximum value for parameter',
504                             'Unit of the parameter']
505        for column, tooltip in enumerate(header_tooltips):
506             self.assertEqual(self.widget._magnet_model.headerData(column,
507                QtCore.Qt.Horizontal, QtCore.Qt.ToolTipRole),
508                         header_tooltips[column])
509
510        # Test rows
511        for row in xrange(self.widget._magnet_model.rowCount()):
512            func_index = self.widget._magnet_model.index(row, 0)
513            self.assertIn(':', self.widget._magnet_model.item(row, 0).text())
514
515
516    def testAddExtraShells(self):
517        """
518        Test how the extra shells are presented
519        """
520        pass
521
522    def testModifyShellsInList(self):
523        """
524        Test the additional rows added by modifying the shells combobox
525        """
526        self.widget.show()
527        # Change the model to multi shell
528        category_index = self.widget.cbCategory.findText("Sphere")
529        self.widget.cbCategory.setCurrentIndex(category_index)
530        model_index = self.widget.cbModel.findText("core_multi_shell")
531        self.widget.cbModel.setCurrentIndex(model_index)
532
533        # Assure we have the combobox available
534        last_row = self.widget._last_model_row
535        func_index = self.widget._model_model.index(last_row-1, 1)
536        self.assertIsInstance(self.widget.lstParams.indexWidget(func_index), QtGui.QComboBox)
537
538        # Change the combo box index
539        self.widget.lstParams.indexWidget(func_index).setCurrentIndex(3)
540
541        # Check that the number of rows increased
542        more_rows = self.widget._model_model.rowCount() - last_row
543        self.assertEqual(more_rows, 6) # 6 new rows: 2 params per index
544
545        # Back to 0
546        self.widget.lstParams.indexWidget(func_index).setCurrentIndex(0)
547        self.assertEqual(self.widget._model_model.rowCount(), last_row)
548
549    def testPlotTheory(self):
550        """
551        See that theory item can produce a chart
552        """
553        # By default, the compute/plot button is disabled
554        self.assertFalse(self.widget.cmdPlot.isEnabled())
555        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
556
557        # Assign a model
558        self.widget.show()
559        # Change the category index so we have a model available
560        category_index = self.widget.cbCategory.findText("Sphere")
561        self.widget.cbCategory.setCurrentIndex(category_index)
562
563        # Check the enablement/text
564        self.assertTrue(self.widget.cmdPlot.isEnabled())
565        self.assertEqual(self.widget.cmdPlot.text(), 'Calculate')
566
567        # Spying on plot update signal
568        spy = QtSignalSpy(self.widget, self.widget.communicate.plotRequestedSignal)
569
570        # Press Calculate
571        QtTest.QTest.mouseClick(self.widget.cmdPlot, QtCore.Qt.LeftButton)
572
573        # Observe cmdPlot caption change
574        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
575
576        # Make sure the signal has NOT been emitted
577        self.assertEqual(spy.count(), 0)
578
579        # Click again
580        QtTest.QTest.mouseClick(self.widget.cmdPlot, QtCore.Qt.LeftButton)
581
582        # This time, we got the update signal
583        self.assertEqual(spy.count(), 0)
584
585    def testPlotData(self):
586        """
587        See that data item can produce a chart
588        """
589        # By default, the compute/plot button is disabled
590        self.assertFalse(self.widget.cmdPlot.isEnabled())
591        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
592
593        self.widget.show()
594
595        # Set data
596        test_data = Data1D(x=[1,2], y=[1,2])
597
598        # Force same data into logic
599        self.widget.logic.data = test_data
600        self.widget.data_is_loaded = True
601
602        # Change the category index so we have a model available
603        category_index = self.widget.cbCategory.findText("Sphere")
604        self.widget.cbCategory.setCurrentIndex(category_index)
605
606        # Check the enablement/text
607        self.assertTrue(self.widget.cmdPlot.isEnabled())
608        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
609
610        # Spying on plot update signal
611        spy = QtSignalSpy(self.widget, self.widget.communicate.plotRequestedSignal)
612
613        # Press Calculate
614        QtTest.QTest.mouseClick(self.widget.cmdPlot, QtCore.Qt.LeftButton)
615
616        # Observe cmdPlot caption did not change
617        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
618
619        # Make sure the signal has been emitted == new plot
620        self.assertEqual(spy.count(), 1)
621
622    def testOnFit1D(self):
623        """
624        Test the threaded fitting call
625        """
626        # Set data
627        test_data = Data1D(x=[1,2], y=[1,2])
628        item = QtGui.QStandardItem()
629        updateModelItem(item, [test_data], "test")
630        # Force same data into logic
631        self.widget.data = item
632        category_index = self.widget.cbCategory.findText("Sphere")
633        self.widget.cbCategory.setCurrentIndex(category_index)
634
635        self.widget.show()
636
637        # Test no fitting params
638        self.widget.parameters_to_fit = []
639
640        with self.assertRaises(ValueError) as error:
641            self.widget.onFit()
642        self.assertEqual(str(error.exception), 'no fitting parameters')
643
644        # Assing fitting params
645        self.widget.parameters_to_fit = ['scale']
646
647        # Spying on status update signal
648        update_spy = QtSignalSpy(self.widget, self.widget.communicate.statusBarUpdateSignal)
649
650        with threads.deferToThread as MagicMock:
651            self.widget.onFit()
652            # thread called
653            self.assertTrue(threads.deferToThread.called)
654            # thread method is 'compute'
655            self.assertEqual(threads.deferToThread.call_args_list[0][0][0].__name__, 'compute')
656
657            # the fit button changed caption and got disabled
658            self.assertEqual(self.widget.cmdFit.text(), 'Running...')
659            self.assertFalse(self.widget.cmdFit.isEnabled())
660
661            # Signal pushed up
662            self.assertEqual(update_spy.count(), 1)
663
664    def testOnFit2D(self):
665        """
666        Test the threaded fitting call
667        """
668        # Set data
669        test_data = Data2D(image=[1.0, 2.0, 3.0],
670                           err_image=[0.01, 0.02, 0.03],
671                           qx_data=[0.1, 0.2, 0.3],
672                           qy_data=[0.1, 0.2, 0.3],
673                           xmin=0.1, xmax=0.3, ymin=0.1, ymax=0.3,
674                           mask=[True, True, True])
675
676        # Force same data into logic
677        item = QtGui.QStandardItem()
678        updateModelItem(item, [test_data], "test")
679        # Force same data into logic
680        self.widget.data = item
681        category_index = self.widget.cbCategory.findText("Sphere")
682        self.widget.cbCategory.setCurrentIndex(category_index)
683
684        self.widget.show()
685
686        # Test no fitting params
687        self.widget.parameters_to_fit = []
688
689        with self.assertRaises(ValueError) as error:
690            self.widget.onFit()
691        self.assertEqual(str(error.exception), 'no fitting parameters')
692
693        # Assing fitting params
694        self.widget.parameters_to_fit = ['scale']
695
696        # Spying on status update signal
697        update_spy = QtSignalSpy(self.widget, self.widget.communicate.statusBarUpdateSignal)
698
699        with threads.deferToThread as MagicMock:
700            self.widget.onFit()
701            # thread called
702            self.assertTrue(threads.deferToThread.called)
703            # thread method is 'compute'
704            self.assertEqual(threads.deferToThread.call_args_list[0][0][0].__name__, 'compute')
705
706            # the fit button changed caption and got disabled
707            self.assertEqual(self.widget.cmdFit.text(), 'Running...')
708            self.assertFalse(self.widget.cmdFit.isEnabled())
709
710            # Signal pushed up
711            self.assertEqual(update_spy.count(), 1)
712
713    def testOnHelp(self):
714        """
715        Test various help pages shown in this widget
716        """
717        #Mock the QWebView method
718        QtWebKit.QWebView.show = MagicMock()
719        QtWebKit.QWebView.load = MagicMock()
720
721        # Invoke the action on default tab
722        self.widget.onHelp()
723        # Check if show() got called
724        self.assertTrue(QtWebKit.QWebView.show.called)
725        # Assure the filename is correct
726        self.assertIn("fitting_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
727
728        # Change the tab to options
729        self.widget.tabFitting.setCurrentIndex(1)
730        self.widget.onHelp()
731        # Check if show() got called
732        self.assertEqual(QtWebKit.QWebView.show.call_count, 2)
733        # Assure the filename is correct
734        self.assertIn("residuals_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
735
736        # Change the tab to smearing
737        self.widget.tabFitting.setCurrentIndex(2)
738        self.widget.onHelp()
739        # Check if show() got called
740        self.assertEqual(QtWebKit.QWebView.show.call_count, 3)
741        # Assure the filename is correct
742        self.assertIn("sm_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
743
744        # Change the tab to poly
745        self.widget.tabFitting.setCurrentIndex(3)
746        self.widget.onHelp()
747        # Check if show() got called
748        self.assertEqual(QtWebKit.QWebView.show.call_count, 4)
749        # Assure the filename is correct
750        self.assertIn("pd_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
751
752        # Change the tab to magnetism
753        self.widget.tabFitting.setCurrentIndex(4)
754        self.widget.onHelp()
755        # Check if show() got called
756        self.assertEqual(QtWebKit.QWebView.show.call_count, 5)
757        # Assure the filename is correct
758        self.assertIn("mag_help.html", QtWebKit.QWebView.load.call_args[0][0].toString())
759
760    def testReadFitPage(self):
761        """
762        Read in the fitpage object and restore state
763        """
764        # Set data
765        test_data = Data1D(x=[1,2], y=[1,2])
766
767        # Force same data into logic
768        self.widget.logic.data = test_data
769        self.widget.data_is_loaded = True
770        category_index = self.widget.cbCategory.findText('Sphere')
771        self.widget.cbCategory.setCurrentIndex(category_index)
772        self.widget.parameters_to_fit = ['scale']
773        # Invoke the tested method
774        fp = self.widget.currentState()
775
776        # Prepare modified fit page
777        fp.current_model = 'onion'
778        fp.is_polydisperse = True
779
780        # Read in modified state
781        self.widget.readFitPage(fp)
782
783        # Check if the widget got updated accordingly
784        self.assertEqual(self.widget.cbModel.currentText(), 'onion')
785        self.assertTrue(self.widget.chkPolydispersity.isChecked())
786
787    def testCurrentState(self):
788        """
789        Set up the fitpage with current state
790        """
791        # Set data
792        test_data = Data1D(x=[1,2], y=[1,2])
793
794        # Force same data into logic
795        self.widget.logic.data = test_data
796        self.widget.data_is_loaded = True
797        category_index = self.widget.cbCategory.findText("Sphere")
798        self.widget.cbCategory.setCurrentIndex(category_index)
799        self.widget.parameters_to_fit = ['scale']
800
801        # Invoke the tested method
802        fp = self.widget.currentState()
803
804        # Test some entries. (Full testing of fp is done in FitPageTest)
805        self.assertIsInstance(fp.data, Data1D)
806        self.assertListEqual(list(fp.data.x), [1,2])
807        self.assertTrue(fp.data_is_loaded)
808        self.assertEqual(fp.current_category, "Sphere")
809        self.assertEqual(fp.current_model, "adsorbed_layer")
810        self.assertListEqual(fp.parameters_to_fit, ['scale'])
811
812    def testPushFitPage(self):
813        """
814        Push current state of fitpage onto stack
815        """
816        # Set data
817        test_data = Data1D(x=[1,2], y=[1,2])
818
819        # Force same data into logic
820        self.widget.logic.data = test_data
821        self.widget.data_is_loaded = True
822        category_index = self.widget.cbCategory.findText("Sphere")
823
824        # Asses the initial state of stack
825        self.assertEqual(self.widget.page_stack, [])
826
827        # Set the undo flag
828        self.widget.undo_supported = True
829        self.widget.cbCategory.setCurrentIndex(category_index)
830        self.widget.parameters_to_fit = ['scale']
831
832        # Check that the stack is updated
833        self.assertEqual(len(self.widget.page_stack), 1)
834
835        # Change another parameter
836        self.widget._model_model.item(2, 1).setText("3.0")
837        # Check that the stack is updated
838        self.assertEqual(len(self.widget.page_stack), 2)
839
840    def testPopFitPage(self):
841        """
842        Pop current state of fitpage from stack
843        """
844        # TODO: to be added when implementing UNDO/REDO
845        pass
846
847    def testOnMainPageChange(self):
848        """
849        Test update  values of modified parameters in models
850        """
851        # select model: cylinder / cylinder
852        category_index = self.widget.cbCategory.findText("Cylinder")
853        self.widget.cbCategory.setCurrentIndex(category_index)
854
855        model_index = self.widget.cbModel.findText("cylinder")
856        self.widget.cbModel.setCurrentIndex(model_index)
857
858        # modify the initial value of length (different from default)
859        # print self.widget.kernel_module.details['length']
860
861        new_value = "333.0"
862        self.widget._model_model.item(5, 1).setText(new_value)
863
864        # name of modified parameter
865        name_modified_param = str(self.widget._model_model.item(5, 0).text())
866
867         # Check the model
868        self.assertEqual(self.widget._model_model.rowCount(), 6)
869        self.assertEqual(self.widget._model_model.columnCount(), 5)
870
871        # Test the header
872        #self.assertEqual(self.widget.lstParams.horizontalHeader().count(), 5)
873        #self.assertFalse(self.widget.lstParams.horizontalHeader().stretchLastSection())
874
875        self.assertEqual(len(self.widget._model_model.header_tooltips), 5)
876        header_tooltips = ['Select parameter for fitting',
877                             'Enter parameter value',
878                             'Enter minimum value for parameter',
879                             'Enter maximum value for parameter',
880                             'Unit of the parameter']
881        for column, tooltip in enumerate(header_tooltips):
882             self.assertEqual(self.widget._model_model.headerData(column,
883                QtCore.Qt.Horizontal, QtCore.Qt.ToolTipRole),
884                         header_tooltips[column])
885
886        # check that the value has been modified in kernel_module
887        self.assertEqual(new_value,
888                         str(self.widget.kernel_module.params[name_modified_param]))
889
890        # check that range of variation for this parameter has NOT been changed
891        print self.widget.kernel_module.details[name_modified_param]
892        self.assertNotIn(new_value, self.widget.kernel_module.details[name_modified_param] )
893
894
895if __name__ == "__main__":
896    unittest.main()
Note: See TracBrowser for help on using the repository browser.