import sys import unittest import webbrowser from bumps import options from PyQt5 import QtGui, QtWidgets from unittest.mock import MagicMock # set up import paths import path_prepare from UnitTesting.TestUtils import QtSignalSpy # Local from sas.qtgui.Perspectives.Fitting.FittingOptions import FittingOptions if not QtWidgets.QApplication.instance(): app = QtWidgets.QApplication(sys.argv) class FittingOptionsTest(unittest.TestCase): '''Test the FittingOptions dialog''' def setUp(self): '''Create FittingOptions dialog''' self.widget = FittingOptions(None, config=options.FIT_CONFIG) def tearDown(self): '''Destroy the GUI''' self.widget.close() self.widget = None def testDefaults(self): '''Test the GUI in its default state''' self.assertIsInstance(self.widget, QtWidgets.QDialog) # Default title self.assertEqual(self.widget.windowTitle(), "Fit Algorithms") # The combo box self.assertIsInstance(self.widget.cbAlgorithm, QtWidgets.QComboBox) self.assertEqual(self.widget.cbAlgorithm.count(), 6) self.assertEqual(self.widget.cbAlgorithm.itemText(0), 'Nelder-Mead Simplex') self.assertEqual(self.widget.cbAlgorithm.itemText(4), 'Levenberg-Marquardt') self.assertEqual(self.widget.cbAlgorithm.currentIndex(), 4) def testAssignValidators(self): """ Check that line edits got correct validators """ # Can't reliably test the method in action, but can easily check the results # DREAM self.assertIsInstance(self.widget.samples_dream.validator(), QtGui.QIntValidator) self.assertIsInstance(self.widget.burn_dream.validator(), QtGui.QIntValidator) self.assertIsInstance(self.widget.pop_dream.validator(), QtGui.QDoubleValidator) self.assertIsInstance(self.widget.thin_dream.validator(), QtGui.QIntValidator) self.assertIsInstance(self.widget.steps_dream.validator(), QtGui.QIntValidator) # DE self.assertIsInstance(self.widget.steps_de.validator(), QtGui.QIntValidator) self.assertIsInstance(self.widget.CR_de.validator(), QtGui.QDoubleValidator) self.assertIsInstance(self.widget.pop_de.validator(), QtGui.QDoubleValidator) self.assertIsInstance(self.widget.F_de.validator(), QtGui.QDoubleValidator) self.assertIsInstance(self.widget.ftol_de.validator(), QtGui.QDoubleValidator) self.assertIsInstance(self.widget.xtol_de.validator(), QtGui.QDoubleValidator) # bottom value for floats and ints self.assertEqual(self.widget.steps_de.validator().bottom(), 0) self.assertEqual(self.widget.CR_de.validator().bottom(), 0) # Behaviour on empty cell self.widget.onAlgorithmChange(3) self.widget.steps_de.setText("") # This should disable the OK button ## self.assertFalse(self.widget.buttonBox.button(QtGui.QDialogButtonBox.Ok).isEnabled()) # Let's put some valid value in lineedit self.widget.steps_de.setText("1") # This should enable the OK button self.assertTrue(self.widget.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).isEnabled()) def testOnAlgorithmChange(self): '''Test the combo box change callback''' # Current ID self.assertEqual(self.widget.current_fitter_id, 'lm') # index = 0 self.widget.onAlgorithmChange(0) # Check Nelder-Mead self.assertEqual(self.widget.stackedWidget.currentIndex(), 1) self.assertEqual(self.widget.current_fitter_id, 'lm') # index = 4 self.widget.onAlgorithmChange(4) # Check Levenberg-Marquad self.assertEqual(self.widget.stackedWidget.currentIndex(), 1) self.assertEqual(self.widget.current_fitter_id, 'lm') def testOnApply(self): '''Test bumps update''' # Spy on the update signal spy_apply = QtSignalSpy(self.widget, self.widget.fit_option_changed) # Set the DREAM optimizer self.widget.cbAlgorithm.setCurrentIndex(2) # Change some values self.widget.init_dream.setCurrentIndex(2) self.widget.steps_dream.setText("50") # Apply the new values self.widget.onApply() self.assertEqual(spy_apply.count(), 1) self.assertIn('DREAM', spy_apply.called()[0]['args'][0]) # Check the parameters self.assertEqual(options.FIT_CONFIG.values['dream']['steps'], 50.0) self.assertEqual(options.FIT_CONFIG.values['dream']['init'], 'cov') # test disabled until pyQt5 works well def testOnHelp(self): ''' Test help display''' webbrowser.open = MagicMock() # Invoke the action on default tab self.widget.onHelp() # Check if show() got called self.assertTrue(webbrowser.open.called) # Assure the filename is correct self.assertIn("optimizer.html", webbrowser.open.call_args[0][0]) # Change the combo index self.widget.cbAlgorithm.setCurrentIndex(2) self.widget.onHelp() # Check if show() got called self.assertEqual(webbrowser.open.call_count, 2) # Assure the filename is correct self.assertIn("fit-dream", webbrowser.open.call_args[0][0]) # Change the index again self.widget.cbAlgorithm.setCurrentIndex(4) self.widget.onHelp() # Check if show() got called self.assertEqual(webbrowser.open.call_count, 3) # Assure the filename is correct self.assertIn("fit-lm", webbrowser.open.call_args[0][0]) def testWidgetFromOptions(self): '''Test the helper function''' # test empty call self.assertIsNone(self.widget.widgetFromOption(None)) # test silly call self.assertIsNone(self.widget.widgetFromOption('poop')) self.assertIsNone(self.widget.widgetFromOption(QtWidgets.QMainWindow())) # Switch to DREAM self.widget.cbAlgorithm.setCurrentIndex(2) # test smart call self.assertIsInstance(self.widget.widgetFromOption('samples'), QtWidgets.QLineEdit) self.assertIsInstance(self.widget.widgetFromOption('init'), QtWidgets.QComboBox) def testUpdateWidgetFromBumps(self): '''Test the widget update''' # modify some value options.FIT_CONFIG.values['newton']['steps'] = 1234 options.FIT_CONFIG.values['newton']['starts'] = 666 options.FIT_CONFIG.values['newton']['xtol'] = 0.01 # Invoke the method for the changed self.widget.updateWidgetFromBumps('newton') # See that the widget picked up the right values self.assertEqual(self.widget.steps_newton.text(), '1234') self.assertEqual(self.widget.starts_newton.text(), '666') self.assertEqual(self.widget.ftol_newton.text(), '1e-06') # default self.assertEqual(self.widget.xtol_newton.text(), '0.01') if __name__ == "__main__": unittest.main()