source: sasview/src/sas/qtgui/Perspectives/Inversion/UnitTesting/InversionPerspectiveTest.py @ 46ca1f4

Last change on this file since 46ca1f4 was 72ecbdf2, checked in by krzywon, 7 years ago

Add a stop calculations button to P(r). Plus unit tests.

  • Property mode set to 100755
File size: 13.7 KB
RevLine 
[d79bb7e]1import time
[50bfab0]2import unittest
3from unittest.mock import MagicMock
4
5from PyQt5 import QtGui, QtWidgets
6
[d79bb7e]7from sas.qtgui.Utilities.GuiUtils import *
[50bfab0]8from sas.qtgui.Perspectives.Inversion.InversionPerspective import InversionWindow
[0662f53]9from sas.qtgui.Perspectives.Inversion.InversionUtils import WIDGETS
[50bfab0]10from sas.qtgui.Plotting.PlotterData import Data1D
11
12import sas.qtgui.Utilities.GuiUtils as GuiUtils
13
14#if not QtWidgets.QApplication.instance():
15app = QtWidgets.QApplication(sys.argv)
16
[0662f53]17
[d79bb7e]18class dummy_manager(object):
19    HELP_DIRECTORY_LOCATION = "html"
20    communicate = Communicate()
21
22    def communicator(self):
23        return self.communicate
24
25
[50bfab0]26class InversionTest(unittest.TestCase):
[0662f53]27    """ Test the Inversion Perspective GUI """
28
[50bfab0]29    def setUp(self):
[0662f53]30        """ Create the InversionWindow """
[d79bb7e]31        self.widget = InversionWindow(dummy_manager())
32        self.widget.show()
[0662f53]33        self.fakeData1 = GuiUtils.HashableStandardItem("A")
34        self.fakeData2 = GuiUtils.HashableStandardItem("B")
35        reference_data1 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0])
[d79bb7e]36        reference_data1.filename = "Test A"
[0662f53]37        reference_data2 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0])
[d79bb7e]38        reference_data2.filename = "Test B"
39        GuiUtils.updateModelItem(self.fakeData1, reference_data1)
40        GuiUtils.updateModelItem(self.fakeData2, reference_data2)
[50bfab0]41
42    def tearDown(self):
[0662f53]43        """ Destroy the InversionWindow """
[d79bb7e]44        self.widget.setClosable(False)
[50bfab0]45        self.widget.close()
46        self.widget = None
47
[0662f53]48    def removeAllData(self):
49        """ Cleanup method to restore widget to its base state """
[d79bb7e]50        if len(self.widget.dataList) > 0:
51            remove_me = list(self.widget._dataList.keys())
52            self.widget.removeData(remove_me)
[0662f53]53
54    def baseGUIState(self):
55        """ Testing base state of Inversion """
56        # base class information
[50bfab0]57        self.assertIsInstance(self.widget, QtWidgets.QWidget)
58        self.assertEqual(self.widget.windowTitle(), "P(r) Inversion Perspective")
[0662f53]59        self.assertFalse(self.widget.isClosable())
[72ecbdf2]60        self.assertFalse(self.widget.isCalculating)
[0662f53]61        # mapper
[50bfab0]62        self.assertIsInstance(self.widget.mapper, QtWidgets.QDataWidgetMapper)
63        self.assertNotEqual(self.widget.mapper.mappedSection(self.widget.dataList), -1)
64        # validators
65        self.assertIsInstance(self.widget.noOfTermsInput.validator(), QtGui.QIntValidator)
66        self.assertIsInstance(self.widget.regularizationConstantInput.validator(), QtGui.QDoubleValidator)
67        self.assertIsInstance(self.widget.maxDistanceInput.validator(), QtGui.QDoubleValidator)
68        self.assertIsInstance(self.widget.minQInput.validator(), QtGui.QDoubleValidator)
69        self.assertIsInstance(self.widget.maxQInput.validator(), QtGui.QDoubleValidator)
70        self.assertIsInstance(self.widget.slitHeightInput.validator(), QtGui.QDoubleValidator)
71        self.assertIsInstance(self.widget.slitWidthInput.validator(), QtGui.QDoubleValidator)
72        # model
73        self.assertEqual(self.widget.model.rowCount(), 22)
[0662f53]74        self.assertEqual(self.widget.model.columnCount(), 1)
75        self.assertEqual(self.widget.mapper.model(), self.widget.model)
76        # buttons
77        self.assertFalse(self.widget.calculateThisButton.isEnabled())
78        self.assertFalse(self.widget.removeButton.isEnabled())
[72ecbdf2]79        self.assertTrue(self.widget.stopButton.isEnabled())
80        self.assertFalse(self.widget.stopButton.isVisible())
[0662f53]81        self.assertFalse(self.widget.regConstantSuggestionButton.isEnabled())
82        self.assertFalse(self.widget.noOfTermsSuggestionButton.isEnabled())
83        self.assertFalse(self.widget.explorerButton.isEnabled())
84        self.assertTrue(self.widget.helpButton.isEnabled())
85        # extra windows and charts
86        self.assertIsNone(self.widget.dmaxWindow)
87        self.assertIsNone(self.widget.prPlot)
88        self.assertIsNone(self.widget.dataPlot)
89        # threads
90        self.assertIsNone(self.widget.calcThread)
91        self.assertIsNone(self.widget.estimationThread)
92        self.assertIsNone(self.widget.estimationThreadNT)
93
94    def baseBatchState(self):
95        """ Testing the base batch fitting state """
96        self.assertTrue(self.widget.allowBatch())
97        self.assertFalse(self.widget.isBatch)
98        self.assertIsNone(self.widget.batchResultsWindow)
99        self.assertFalse(self.widget.calculateAllButton.isEnabled())
100        self.assertEqual(len(self.widget.batchResults), 0)
101        self.assertEqual(len(self.widget.batchComplete), 0)
102        self.widget.closeBatchResults()
103        self.assertIsNone(self.widget.batchResultsWindow)
104
105    def zeroDataSetState(self):
106        """ Testing the base data state of the GUI """
107        # data variables
108        self.assertIsNone(self.widget._data)
109        self.assertEqual(len(self.widget._dataList), 0)
110        self.assertEqual(self.widget.nTermsSuggested, 10)
111        # inputs
112        self.assertEqual(len(self.widget.dataList), 0)
113        self.assertEqual(self.widget.backgroundInput.text(), "0.0")
114        self.assertEqual(self.widget.minQInput.text(), "")
[d79bb7e]115        self.assertEqual(self.widget.maxQInput.text(), "")
[0662f53]116        self.assertEqual(self.widget.regularizationConstantInput.text(), "0.0001")
117        self.assertEqual(self.widget.noOfTermsInput.text(), "10")
118        self.assertEqual(self.widget.maxDistanceInput.text(), "140.0")
119
120    def oneDataSetState(self):
121        """ Testing the base data state of the GUI """
122        # Test the globals after first sent
123        self.assertEqual(len(self.widget._dataList), 1)
124        self.assertEqual(self.widget.dataList.count(), 1)
125        # See that the buttons are now enabled properly
[d79bb7e]126        self.widget.enableButtons()
[0662f53]127        self.assertFalse(self.widget.calculateAllButton.isEnabled())
128        self.assertTrue(self.widget.calculateThisButton.isEnabled())
129        self.assertTrue(self.widget.removeButton.isEnabled())
130        self.assertTrue(self.widget.explorerButton.isEnabled())
[50bfab0]131
[0662f53]132    def twoDataSetState(self):
133        """ Testing the base data state of the GUI """
134        # Test the globals after first sent
135        self.assertEqual(len(self.widget._dataList), 2)
[50bfab0]136        self.assertEqual(self.widget.dataList.count(), 2)
[0662f53]137        # See that the buttons are now enabled properly
[d79bb7e]138        self.widget.enableButtons()
[50bfab0]139        self.assertTrue(self.widget.calculateThisButton.isEnabled())
[d79bb7e]140        self.assertTrue(self.widget.calculateAllButton.isEnabled())
[50bfab0]141        self.assertTrue(self.widget.removeButton.isEnabled())
142        self.assertTrue(self.widget.explorerButton.isEnabled())
143
[0662f53]144    def testDefaults(self):
145        """ Test the GUI in its default state """
146        self.baseGUIState()
147        self.zeroDataSetState()
148        self.baseBatchState()
[d79bb7e]149        self.removeAllData()
[50bfab0]150
151    def testAllowBatch(self):
[0662f53]152        """ Batch P(r) Tests """
153        self.baseBatchState()
[d79bb7e]154        self.widget.setData([self.fakeData1])
155        self.oneDataSetState()
156        self.widget.setData([self.fakeData2])
157        self.twoDataSetState()
158        self.widget.calculateAllButton.click()
[72ecbdf2]159        self.assertTrue(self.widget.isCalculating)
160        self.assertTrue(self.widget.isBatch)
161        self.assertTrue(self.widget.stopButton.isVisible())
162        self.assertTrue(self.widget.stopButton.isEnabled())
[6bd0d81]163        self.assertIsNotNone(self.widget.batchResultsWindow)
164        self.assertTrue(self.widget.batchResultsWindow.cmdHelp.isEnabled())
[d79bb7e]165        self.assertEqual(self.widget.batchResultsWindow.tblParams.columnCount(), 9)
166        self.assertEqual(self.widget.batchResultsWindow.tblParams.rowCount(), 2)
[72ecbdf2]167        # Test stop button
168        self.widget.stopButton.click()
169        self.assertTrue(self.widget.batchResultsWindow.isVisible())
170        self.assertFalse(self.widget.stopButton.isVisible())
171        self.assertTrue(self.widget.stopButton.isEnabled())
172        self.assertFalse(self.widget.isBatch)
173        self.assertFalse(self.widget.isCalculating)
[d79bb7e]174        self.widget.batchResultsWindow.close()
[6bd0d81]175        self.assertIsNone(self.widget.batchResultsWindow)
[d79bb7e]176        # Last test
177        self.removeAllData()
178        self.baseBatchState()
[50bfab0]179
[0662f53]180    def testSetData(self):
181        """ Check if sending data works as expected """
182        self.zeroDataSetState()
183        self.widget.setData([self.fakeData1])
184        self.oneDataSetState()
185        self.widget.setData([self.fakeData1])
186        self.oneDataSetState()
187        self.widget.setData([self.fakeData2])
188        self.twoDataSetState()
189        self.removeAllData()
190        self.zeroDataSetState()
[d79bb7e]191        self.removeAllData()
[0662f53]192
193    def testRemoveData(self):
194        """ Test data removal from widget """
195        self.widget.setData([self.fakeData1, self.fakeData2])
196        self.twoDataSetState()
197        # Remove data 0
198        self.widget.removeData()
199        self.oneDataSetState()
[d79bb7e]200        self.removeAllData()
[50bfab0]201
[0662f53]202    def testClose(self):
203        """ Test methods related to closing the window """
204        self.assertFalse(self.widget.isClosable())
205        self.widget.close()
[d79bb7e]206        self.assertTrue(self.widget.isMinimized())
[6bd0d81]207        self.assertIsNone(self.widget.dmaxWindow)
208        self.assertIsNone(self.widget.batchResultsWindow)
[0662f53]209        self.widget.setClosable(False)
210        self.assertFalse(self.widget.isClosable())
211        self.widget.close()
[d79bb7e]212        self.assertTrue(self.widget.isMinimized())
[0662f53]213        self.widget.setClosable(True)
214        self.assertTrue(self.widget.isClosable())
215        self.widget.setClosable()
216        self.assertTrue(self.widget.isClosable())
[d79bb7e]217        self.removeAllData()
[50bfab0]218
219    def testGetNFunc(self):
[0662f53]220        """ test nfunc getter """
[50bfab0]221        # Float
222        self.widget.noOfTermsInput.setText("10.0")
223        self.assertEqual(self.widget.getNFunc(), 10)
224        # Int
225        self.widget.noOfTermsInput.setText("980")
226        self.assertEqual(self.widget.getNFunc(), 980)
227        # Empty
228        with self.assertLogs(level='ERROR') as cm:
229            self.widget.noOfTermsInput.setText("")
230            n = self.widget.getNFunc()
[72ecbdf2]231            self.assertEqual(cm.output, ['ERROR:sas.qtgui.Perspectives.Inversion.InversionPerspective:Incorrect number of terms specified: '])
[50bfab0]232        self.assertEqual(self.widget.getNFunc(), 10)
233        # string
234        with self.assertLogs(level='ERROR') as cm:
235            self.widget.noOfTermsInput.setText("Nordvest Pizza")
236            n = self.widget.getNFunc()
[72ecbdf2]237            self.assertEqual(cm.output, ['ERROR:sas.qtgui.Perspectives.Inversion.InversionPerspective:Incorrect number of terms specified: Nordvest Pizza'])
[50bfab0]238        self.assertEqual(self.widget.getNFunc(), 10)
[d79bb7e]239        self.removeAllData()
[50bfab0]240
241    def testSetCurrentData(self):
[0662f53]242        """ test current data setter """
243        self.widget.setData([self.fakeData1, self.fakeData2])
[50bfab0]244
245        # Check that the current data is reference2
[0662f53]246        self.assertEqual(self.widget._data, self.fakeData2)
[50bfab0]247        # Set the ref to none
248        self.widget.setCurrentData(None)
[0662f53]249        self.assertEqual(self.widget._data, self.fakeData2)
[50bfab0]250        # Set the ref to wrong type
251        with self.assertRaises(AttributeError):
252            self.widget.setCurrentData("Afandi Kebab")
[0662f53]253        # Set the reference to ref1
254        self.widget.setCurrentData(self.fakeData1)
255        self.assertEqual(self.widget._data, self.fakeData1)
[d79bb7e]256        self.removeAllData()
[0662f53]257
[d79bb7e]258    def testModelChanged(self):
259        """ Test setting the input and the model and vice-versa """
260        # Initial values
261        self.assertEqual(self.widget._calculator.get_dmax(), 140.0)
262        self.assertEqual(self.widget._calculator.get_qmax(), -1.0)
263        self.assertEqual(self.widget._calculator.get_qmin(), -1.0)
264        self.assertEqual(self.widget._calculator.slit_height, 0.0)
265        self.assertEqual(self.widget._calculator.slit_width, 0.0)
266        self.assertEqual(self.widget._calculator.alpha, 0.0001)
267        # Set new values
268        self.widget.maxDistanceInput.setText("1.0")
269        self.widget.maxQInput.setText("3.0")
270        self.widget.minQInput.setText("5.0")
271        self.widget.slitHeightInput.setText("7.0")
272        self.widget.slitWidthInput.setText("9.0")
273        self.widget.regularizationConstantInput.setText("11.0")
274        # Check new values
275        self.assertEqual(self.widget._calculator.get_dmax(), 1.0)
276        self.assertEqual(self.widget._calculator.get_qmax(), 3.0)
277        self.assertEqual(self.widget._calculator.get_qmin(), 5.0)
278        self.assertEqual(self.widget._calculator.slit_height, 7.0)
279        self.assertEqual(self.widget._calculator.slit_width, 9.0)
280        self.assertEqual(self.widget._calculator.alpha, 11.0)
281        # Change model directly
282        self.widget.model.setItem(WIDGETS.W_MAX_DIST, QtGui.QStandardItem("2.0"))
283        self.widget.model.setItem(WIDGETS.W_QMIN, QtGui.QStandardItem("4.0"))
284        self.widget.model.setItem(WIDGETS.W_QMAX, QtGui.QStandardItem("6.0"))
285        self.widget.model.setItem(WIDGETS.W_SLIT_HEIGHT, QtGui.QStandardItem("8.0"))
286        self.widget.model.setItem(WIDGETS.W_SLIT_WIDTH, QtGui.QStandardItem("10.0"))
287        self.widget.model.setItem(WIDGETS.W_REGULARIZATION, QtGui.QStandardItem("12.0"))
288        # Check values
289        self.assertEqual(self.widget._calculator.get_dmax(), 2.0)
290        self.assertEqual(self.widget._calculator.get_qmin(), 4.0)
291        self.assertEqual(self.widget._calculator.get_qmax(), 6.0)
292        self.assertEqual(self.widget._calculator.slit_height, 8.0)
293        self.assertEqual(self.widget._calculator.slit_width, 10.0)
294        self.assertEqual(self.widget._calculator.alpha, 12.0)
295        self.removeAllData()
[0662f53]296
[6bd0d81]297    def testOpenExplorerWindow(self):
[0662f53]298        """ open Dx window """
[6bd0d81]299        self.assertIsNone(self.widget.dmaxWindow)
300        self.assertFalse(self.widget.explorerButton.isEnabled())
[0662f53]301        self.widget.openExplorerWindow()
[6bd0d81]302        self.assertIsNotNone(self.widget.dmaxWindow)
[0662f53]303        self.assertTrue(self.widget.dmaxWindow.isVisible())
[6bd0d81]304        self.assertTrue(self.widget.dmaxWindow.windowTitle() == "Dₐₓ Explorer")
[50bfab0]305
306
307if __name__ == "__main__":
308    unittest.main()
Note: See TracBrowser for help on using the repository browser.