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

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

Added tab-dependent help display in fiting

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