source: sasview/src/sas/qtgui/Calculators/UnitTesting/GenericScatteringCalculatorTest.py @ 60a4e71

Last change on this file since 60a4e71 was e90988c, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Show help pages in default browser. Fixed some help links and modified unit tests. SASVIEW-800

  • Property mode set to 100644
File size: 20.1 KB
Line 
1import sys
2import time
3import numpy
4import unittest
5from PyQt5 import QtGui, QtWidgets
6from PyQt5.QtTest import QTest
7
8from PyQt5.QtCore import Qt
9from unittest.mock import MagicMock
10from unittest.mock import patch
11
12# set up import paths
13import path_prepare
14
15from mpl_toolkits.mplot3d import Axes3D
16from UnitTesting.TestUtils import QtSignalSpy
17from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
18from sas.qtgui.Calculators.GenericScatteringCalculator import GenericScatteringCalculator
19from sas.qtgui.Calculators.GenericScatteringCalculator import Plotter3D
20
21from sas.qtgui.MainWindow.DataManager import DataManager
22from sas.qtgui.MainWindow.GuiManager import GuiManager
23from sas.qtgui.Utilities.GuiUtils import *
24from sas.sascalc.calculator import sas_gen
25
26if not QtWidgets.QApplication.instance():
27    app = QtWidgets.QApplication(sys.argv)
28
29class GenericScatteringCalculatorTest(unittest.TestCase):
30    """Test the GenericScatteringCalculator"""
31    def setUp(self):
32        """Create the GenericScatteringCalculator"""
33        class dummy_manager(object):
34            def communicator(self):
35                return Communicate()
36
37        self.widget = GenericScatteringCalculator(dummy_manager())
38
39    def tearDown(self):
40        """Destroy the GenericScatteringCalculator"""
41        self.widget.close()
42        self.widget = None
43
44
45    def testDefaults(self):
46        """Test the GUI in its default state"""
47        self.assertIsInstance(self.widget, QtWidgets.QWidget)
48        self.assertEqual(self.widget.windowTitle(), "Generic SAS Calculator")
49
50        self.assertIn('trigger_plot_3d', dir(self.widget))
51
52        # Buttons
53        self.assertEqual(self.widget.txtData.text(), "Default SLD Profile")
54        self.assertEqual(self.widget.cmdLoad.text(), "Load")
55        self.assertEqual(self.widget.cmdDraw.text(), "Draw")
56        self.assertEqual(self.widget.cmdCompute.text(), "Compute")
57        self.assertEqual(self.widget.cmdReset.text(), "Reset")
58        self.assertEqual(self.widget.cmdClose.text(), "Close")
59        self.assertEqual(self.widget.cmdHelp.text(), "Help")
60        self.assertEqual(self.widget.cmdDrawpoints.text(), "Draw Points")
61        self.assertEqual(self.widget.cmdSave.text(), "Save SLD Data")
62
63        self.assertEqual(self.widget.txtBackground.text(), '0.0')
64        self.assertEqual(self.widget.txtScale.text(), '1.0')
65        self.assertEqual(self.widget.txtSolventSLD.text(), '0.0')
66        self.assertEqual(self.widget.txtTotalVolume.text(), '216000.0')
67        self.assertEqual(self.widget.txtUpFracIn.text(), '1.0')
68        self.assertEqual(self.widget.txtUpFracOut.text(), '1.0')
69        self.assertEqual(self.widget.txtUpTheta.text(), '0.0')
70        self.assertEqual(self.widget.txtNoQBins.text(), '50')
71        self.assertEqual(self.widget.txtQxMax.text(), '0.3')
72        self.assertEqual(self.widget.txtNoPixels.text(), '1000')
73        self.assertEqual(self.widget.txtMx.text(), '0')
74        self.assertEqual(self.widget.txtMy.text(), '0')
75        self.assertEqual(self.widget.txtMz.text(), '0')
76        self.assertEqual(self.widget.txtNucl.text(), '6.97e-06')
77        self.assertEqual(self.widget.txtXnodes.text(), '10')
78        self.assertEqual(self.widget.txtYnodes.text(), '10')
79        self.assertEqual(self.widget.txtZnodes.text(), '10')
80        self.assertEqual(self.widget.txtXstepsize.text(), '6')
81        self.assertEqual(self.widget.txtYstepsize.text(), '6')
82        self.assertEqual(self.widget.txtZstepsize.text(), '6')
83
84        # Comboboxes
85        self.assertFalse(self.widget.cbOptionsCalc.isVisible())
86        self.assertFalse(self.widget.cbOptionsCalc.isEditable())
87        self.assertEqual(self.widget.cbOptionsCalc.count(), 2)
88        self.assertEqual(self.widget.cbOptionsCalc.currentIndex(), 0)
89        self.assertListEqual([self.widget.cbOptionsCalc.itemText(i) for i in
90                              range(self.widget.cbOptionsCalc.count())],
91                             ['Fixed orientation', 'Debye full avg.'])
92
93        self.assertEqual(self.widget.cbShape.count(), 2)
94        self.assertEqual(self.widget.cbShape.currentIndex(), 0)
95        self.assertListEqual([self.widget.cbShape.itemText(i) for i in
96                              range(self.widget.cbShape.count())],
97                             ['Rectangular', 'Ellipsoid'])
98        self.assertFalse(self.widget.cbShape.isEditable())
99        # disable buttons
100        self.assertFalse(self.widget.cmdSave.isEnabled())
101        self.assertFalse(self.widget.cmdDraw.isEnabled())
102        self.assertFalse(self.widget.cmdDrawpoints.isEnabled())
103
104    def testHelpButton(self):
105        """ Assure help file is shown """
106        self.widget.manager.showHelp = MagicMock()
107        self.widget.onHelp()
108        self.assertTrue(self.widget.manager.showHelp.called_once())
109        args = self.widget.manager.showHelp.call_args
110        self.assertIn('sas_calculator_help.html', args[0][0])
111
112    def testValidator(self):
113        """ Test the inputs when validators had been defined """
114        # Background, Volume and Scale should be positive
115        txtEdit_positive = [self.widget.txtBackground,
116                            self.widget.txtTotalVolume,
117                            self.widget.txtScale]
118
119        for item in txtEdit_positive:
120            item.setText('-1')
121            state = item.validator().validate(item.text(), 0)[0]
122            self.assertEqual(state, QtGui.QValidator.Invalid)
123
124        for item in txtEdit_positive:
125            item.setText('2')
126            state = item.validator().validate(item.text(), 0)[0]
127            self.assertEqual(state, QtGui.QValidator.Acceptable)
128
129        for item in txtEdit_positive:
130            item.setText('abc')
131            state = item.validator().validate(item.text(), 0)[0]
132            self.assertEqual(state, QtGui.QValidator.Invalid)
133
134        # Fraction of spin up between 0 and 1
135        txtEdit_0_1 = [self.widget.txtUpFracIn, self.widget.txtUpFracOut]
136
137        for item in txtEdit_0_1:
138            item.setText('-1.04546')
139            state = item.validator().validate(item.text(), 0)[0]
140            self.assertEqual(state, QtGui.QValidator.Invalid)
141
142        for item in txtEdit_0_1:
143            item.setText('2.00000')
144            state = item.validator().validate(item.text(), 0)[0]
145            self.assertEqual(state, QtGui.QValidator.Invalid)
146
147        for item in txtEdit_0_1:
148            item.setText('0.000000005')
149            state = item.validator().validate(item.text(), 0)[0]
150            self.assertEqual(state, QtGui.QValidator.Acceptable)
151
152        # Test text edits related to Q:
153        # 0< Qmax < 1000, 2 <= Qbins <= 1000
154        txtEdit_q_values = [self.widget.txtNoQBins, self.widget.txtQxMax]
155        for item in txtEdit_q_values:
156            item.setText('-1.01')
157            state = item.validator().validate(item.text(), 0)[0]
158            self.assertEqual(state, QtGui.QValidator.Invalid)
159
160        for item in txtEdit_q_values:
161            item.setText('1500.01')
162            state = item.validator().validate(item.text(), 0)[0]
163            self.assertEqual(state, QtGui.QValidator.Invalid)
164
165        self.widget.txtNoQBins.setText('1.5')
166        self.assertEqual(
167            self.widget.txtNoQBins.validator().validate(item.text(), 0)[0],
168            QtGui.QValidator.Invalid)
169
170        self.widget.txtQxMax.setText('1.5')
171        self.assertEqual(
172            self.widget.txtQxMax.validator().validate(item.text(), 0)[0],
173            QtGui.QValidator.Acceptable)
174
175    def testLoadedSLDData(self):
176        """
177        Load sld data and check modifications of GUI
178        """
179        filename = os.path.join("UnitTesting", "sld_file.sld")
180        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=[filename, ''])
181        self.widget.loadFile()
182
183        # check modification of text in Load button
184        self.assertEqual(self.widget.cmdLoad.text(), 'Loading...')
185        # wait a bit for data to be loaded
186        time.sleep(0.1)
187        # check updated values in ui, read from loaded file
188        self.assertEqual(self.widget.txtData.text(), 'sld_file.sld')
189        self.assertEqual(self.widget.txtTotalVolume.text(), '402408.0')
190        self.assertEqual(self.widget.txtNoPixels.text(), '552')
191        self.assertFalse(self.widget.txtNoPixels.isEnabled())
192
193        # check disabled TextEdits according to data format
194        self.assertFalse(self.widget.txtUpFracIn.isEnabled())
195        self.assertFalse(self.widget.txtUpFracOut.isEnabled())
196        self.assertFalse(self.widget.txtUpFracOut.isEnabled())
197        self.assertFalse(self.widget.txtNoPixels.isEnabled())
198
199        # check enabled draw buttons
200        self.assertTrue(self.widget.cmdDraw.isEnabled())
201        self.assertTrue(self.widget.cmdDrawpoints.isEnabled())
202        self.widget.show()
203        self.assertTrue(self.widget.isVisible())
204        self.assertFalse(self.widget.cbOptionsCalc.isVisible())
205
206        # check that text of loadButton is back to initial state
207        self.assertEqual(self.widget.cmdLoad.text(), 'Load')
208        # check values and enabled / disabled for
209        # Mx,y,z x,y,znodes and x,y,zstepsize buttons
210        self.assertFalse(self.widget.txtMx.isEnabled())
211        self.assertAlmostEqual(float(self.widget.txtMx.text()), 8.0795e-07, 4)
212        self.assertFalse(self.widget.txtMy.isEnabled())
213        self.assertAlmostEqual(float(self.widget.txtMy.text()), 8.0795e-07, 4)
214        self.assertFalse(self.widget.txtMz.isEnabled())
215        self.assertAlmostEqual(float(self.widget.txtMz.text()), 3.1739e-07, 4)
216        self.assertTrue(self.widget.txtNucl.isEnabled())
217        self.assertEqual(self.widget.txtNucl.text(), '0')
218
219        self.assertFalse(self.widget.txtXnodes.isEnabled())
220        self.assertEqual(self.widget.txtXnodes.text(), '10')
221        self.assertFalse(self.widget.txtYnodes.isEnabled())
222        self.assertEqual(self.widget.txtYnodes.text(), '10')
223        self.assertFalse(self.widget.txtZnodes.isEnabled())
224        self.assertEqual(self.widget.txtZnodes.text(), '10')
225
226        self.assertFalse(self.widget.txtXstepsize.isEnabled())
227        self.assertEqual(self.widget.txtXstepsize.text(), '9')
228        self.assertFalse(self.widget.txtYstepsize.isEnabled())
229        self.assertEqual(self.widget.txtYstepsize.text(), '9')
230        self.assertFalse(self.widget.txtZstepsize.isEnabled())
231        self.assertEqual(self.widget.txtZstepsize.text(), '9')
232
233        self.assertTrue(self.widget.sld_data.is_data)
234
235        # self.assertTrue(self.widget.trigger_plot_3d)
236
237
238    def testLoadedPDBButton(self):
239        """
240        Load pdb data and check modifications of GUI
241        """
242        filename = os.path.join("UnitTesting", "diamdsml.pdb")
243
244        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=[filename, ''])
245        self.widget.loadFile()
246
247        # check modification of text in Load button
248        self.assertEqual(self.widget.cmdLoad.text(), 'Loading...')
249
250        time.sleep(1)
251        # check updated values in ui, read from loaded file
252        # TODO to be changed
253        self.assertEqual(self.widget.txtData.text(), 'diamdsml.pdb')
254        self.assertEqual(self.widget.txtTotalVolume.text(), '170.950584161')
255        self.assertEqual(self.widget.txtNoPixels.text(), '18')
256
257        # check disabled TextEdits according to data format
258        self.assertFalse(self.widget.txtUpFracIn.isEnabled())
259        self.assertFalse(self.widget.txtUpFracOut.isEnabled())
260        self.assertFalse(self.widget.txtUpFracOut.isEnabled())
261        self.assertFalse(self.widget.txtNoPixels.isEnabled())
262        # check enabled draw buttons
263        self.assertTrue(self.widget.cmdDraw.isEnabled())
264        self.assertTrue(self.widget.cmdDrawpoints.isEnabled())
265        # fixed orientation
266        self.widget.show()
267        self.assertTrue(self.widget.isVisible())
268        self.assertTrue(self.widget.cbOptionsCalc.isVisible())
269        # check that text of loadButton is back to initial state
270        self.assertEqual(self.widget.cmdLoad.text(), 'Load')
271        self.assertTrue(self.widget.cmdLoad.isEnabled())
272
273        # check values and enabled / disabled for
274        # Mx,y,z x,y,znodes and x,y,zstepsize buttons
275        self.assertFalse(self.widget.txtMx.isEnabled())
276        self.assertEqual(self.widget.txtMx.text(), '0')
277        self.assertFalse(self.widget.txtMy.isEnabled())
278        self.assertEqual(self.widget.txtMy.text(), '0')
279        self.assertFalse(self.widget.txtMz.isEnabled())
280        self.assertEqual(self.widget.txtMz.text(), '0')
281        self.assertFalse(self.widget.txtNucl.isEnabled())
282        self.assertAlmostEqual(float(self.widget.txtNucl.text()), 7.0003e-06, 4)
283
284        self.assertFalse(self.widget.txtXnodes.isEnabled())
285        self.assertEqual(self.widget.txtXnodes.text(), 'NaN')
286        self.assertFalse(self.widget.txtYnodes.isEnabled())
287        self.assertEqual(self.widget.txtYnodes.text(), 'NaN')
288        self.assertFalse(self.widget.txtZnodes.isEnabled())
289        self.assertEqual(self.widget.txtZnodes.text(), 'NaN')
290
291        self.assertFalse(self.widget.txtXstepsize.isEnabled())
292        self.assertEqual(self.widget.txtXstepsize.text(), 'NaN')
293        self.assertFalse(self.widget.txtYstepsize.isEnabled())
294        self.assertEqual(self.widget.txtYstepsize.text(), 'NaN')
295        self.assertFalse(self.widget.txtZstepsize.isEnabled())
296        self.assertEqual(self.widget.txtZstepsize.text(), 'NaN')
297
298        self.assertTrue(self.widget.sld_data.is_data)
299
300    # TODO
301    def testLoadedOMFButton(self):
302        """
303        Load omf data and check modifications of GUI
304        """
305        filename = os.path.join("UnitTesting", "A_Raw_Example-1.omf")
306
307        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=[filename, ''])
308        self.widget.loadFile()
309        self.assertEqual(self.widget.cmdLoad.text(), 'Loading...')
310        time.sleep(2)
311
312        self.assertEqual(self.widget.txtData.text(), 'A_Raw_Example-1.omf')
313        self.assertEqual(self.widget.txtTotalVolume.text(), '128000000.0')
314        self.assertEqual(self.widget.txtNoPixels.text(), '16000')
315
316        # check disabled TextEdits according to data format
317        self.assertFalse(self.widget.txtUpFracIn.isEnabled())
318        self.assertFalse(self.widget.txtUpFracOut.isEnabled())
319        self.assertFalse(self.widget.txtUpFracOut.isEnabled())
320        self.assertFalse(self.widget.txtNoPixels.isEnabled())
321
322        # check enabled draw buttons
323        self.assertTrue(self.widget.cmdDraw.isEnabled())
324        self.assertTrue(self.widget.cmdDrawpoints.isEnabled())
325
326        # check that text of loadButton is back to initial state
327        self.assertEqual(self.widget.cmdLoad.text(), 'Load')
328        self.assertTrue(self.widget.cmdLoad.isEnabled())
329
330        # check values and enabled / disabled for
331        # Mx,y,z x,y,znodes and x,y,zstepsize buttons
332        self.assertFalse(self.widget.txtMx.isEnabled())
333        self.assertAlmostEqual(float(self.widget.txtMx.text()), 7.855e-09, 4)
334        self.assertFalse(self.widget.txtMy.isEnabled())
335        self.assertAlmostEqual(float(self.widget.txtMy.text()), 4.517e-08, 4)
336        self.assertFalse(self.widget.txtMz.isEnabled())
337        self.assertAlmostEqual(float(self.widget.txtMz.text()), 9.9511e-10, 4)
338        self.assertTrue(self.widget.txtNucl.isEnabled())
339        self.assertEqual(self.widget.txtNucl.text(), '0')
340
341        self.assertFalse(self.widget.txtXnodes.isEnabled())
342        self.assertEqual(self.widget.txtXnodes.text(), '40')
343        self.assertFalse(self.widget.txtYnodes.isEnabled())
344        self.assertEqual(self.widget.txtYnodes.text(), '40')
345        self.assertFalse(self.widget.txtZnodes.isEnabled())
346        self.assertEqual(self.widget.txtZnodes.text(), '10')
347
348        self.assertFalse(self.widget.txtXstepsize.isEnabled())
349        self.assertEqual(self.widget.txtXstepsize.text(), '20')
350        self.assertFalse(self.widget.txtYstepsize.isEnabled())
351        self.assertEqual(self.widget.txtYstepsize.text(), '20')
352        self.assertFalse(self.widget.txtZstepsize.isEnabled())
353        self.assertEqual(self.widget.txtZstepsize.text(), '20')
354
355    def testReset(self):
356        """
357        Test reset button when GUI has been modified
358        """
359        # modify gui
360        self.widget.txtBackground.setText('50.0')
361        # apply reset
362        self.widget.onReset()
363        # check that we get back to the initial state
364        self.assertEqual(self.widget.txtBackground.text(), '0.0')
365
366    # TODO check plots
367    def testCompute(self):
368        """
369        Test compute button
370        """
371        # load data
372        filename = os.path.join("UnitTesting", "diamdsml.pdb")
373
374        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=[filename, ''])
375        self.widget.loadFile()
376        time.sleep(1)
377        QTest.mouseClick(self.widget.cmdCompute, Qt.LeftButton)
378        # check modification of text of Compute button
379        self.assertEqual(self.widget.cmdCompute.text(), 'Wait...')
380        self.assertFalse(self.widget.cmdCompute.isEnabled())
381
382        #self.widget.complete([numpy.ones(1), numpy.zeros(1), numpy.zeros(1)], update=None)
383        #self.assertEqual(self.widget.cmdCompute.text(), 'Compute')
384        #self.assertTrue(self.widget.cmdCompute.isEnabled())
385
386    # TODO
387    def testDrawButton(self):
388        """
389        Test Draw buttons for 3D plots with and without arrows
390        """
391        self.assertFalse(self.widget.cmdDraw.isEnabled())
392        filename = os.path.join("UnitTesting", "diamdsml.pdb")
393        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=[filename,''])
394        self.widget.loadFile()
395        self.assertEqual(self.widget.cmdLoad.text(), 'Loading...')
396        time.sleep(1)
397
398        self.assertTrue(self.widget.cmdDraw.isEnabled())
399        QTest.mouseClick(self.widget.cmdDraw, Qt.LeftButton)
400
401        self.assertTrue(self.widget.cmdDrawpoints.isEnabled())
402        QTest.mouseClick(self.widget.cmdDrawpoints, Qt.LeftButton)
403
404    def testCloseButton(self):
405        closeButton = self.widget.cmdClose
406        QTest.mouseClick(closeButton, Qt.LeftButton)
407
408    def testSaveFile(self):
409        """
410        Test Save feature to .sld file
411        """
412        filename = os.path.join("UnitTesting", "sld_file.sld")
413
414        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=[filename, ''])
415        self.widget.loadFile()
416
417        time.sleep(0.1)
418
419        filename1 = "test"
420        QtWidgets.QFileDialog.getSaveFileName = MagicMock(return_value=[filename1, ''])
421
422        QTest.mouseClick(self.widget.cmdSave, Qt.LeftButton)
423        self.widget.onSaveFile()
424        self.assertTrue(os.path.isfile(filename1 + '.sld'))
425        self.assertTrue(os.path.getsize(filename1 + '.sld') > 0)
426
427        os.remove("test.sld")
428
429
430class Plotter3DTest(unittest.TestCase):
431    """ Test 3D plots in real space.
432    The implementation is temporarily in the same script as the Generic SAS
433    calculator"""
434    def setUp(self):
435        """create"""
436        parent_test = MagicMock()
437        self.plotter = Plotter3D(parent=parent_test, graph_title='test')
438        self.data = sas_gen.MagSLD(numpy.array([1.0, 2.0, 3.0, 4.0]),
439                                   numpy.array([10.0, 11.0, 12.0, 13.0]),
440                                   numpy.array([0.1, 0.2, 0.3, 0.4]),
441                                   numpy.zeros(4),
442                                   numpy.zeros(4),
443                                   numpy.zeros(4),
444                                   numpy.zeros(4))
445        self.data.sld_n = [0, 6.97e-06, 6.97e-06, 6.97e-06]
446        self.data.set_pix_type('pixel')
447        self.data.pix_symbol = numpy.repeat('pixel', 4)
448
449    def tearDown(self):
450        """ Destroy"""
451        self.plotter = None
452        self.data = None
453
454    def testDataProperty(self):
455        self.plotter.data = self.data
456        self.assertEqual(self.plotter.data, self.data)
457        self.assertTrue(self.plotter.graph_title, 'test')
458        self.assertFalse(self.plotter.data.has_conect)
459
460    def testShowNoPlot(self):
461        FigureCanvas.draw_idle = MagicMock()
462        FigureCanvas.draw = MagicMock()
463        self.plotter.showPlot(data=None)
464        self.assertFalse(FigureCanvas.draw_idle.called)
465        self.assertFalse(FigureCanvas.draw.called)
466
467    def testShow3DPlot(self):
468        FigureCanvas.draw = MagicMock()
469        Axes3D.plot = MagicMock()
470
471        self.plotter.data = self.data
472        self.plotter.showPlot(data=self.plotter.data)
473        self.assertTrue(Axes3D.plot.called)
474        self.assertTrue(FigureCanvas.draw.called)
475
476
477if __name__ == "__main__":
478    unittest.main()
Note: See TracBrowser for help on using the repository browser.