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

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 06b0138 was 06b0138, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Polydispersity support: cleanup and unit tests SASVIEW-575

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