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

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 6cbf8a5 was 9ea43c82, checked in by Tim Snow <tim.snow@…>, 7 years ago

Fixed unit test

Initially I also had this test passing, however, after deleting (and rebuilding) the main build directory it began failing. This change does reflect the current code present in the Perspectives/Fitting/ViewDelegate?.py file.

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