source: sasview/src/sas/qtgui/Utilities/UnitTesting/AddMultEditorTest.py @ 27689dc

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

Updated unit tests

  • Property mode set to 100644
File size: 12.5 KB
Line 
1import sys
2import os
3import unittest
4import webbrowser
5import tempfile
6from unittest.mock import MagicMock, patch
7
8from PyQt5 import QtGui
9from PyQt5 import QtWidgets
10
11# set up import paths
12import path_prepare
13
14from sas.qtgui.Utilities.GuiUtils import Communicate
15
16# Local
17from sas.qtgui.Utilities.AddMultEditor import AddMultEditor
18
19if not QtWidgets.QApplication.instance():
20    app = QtWidgets.QApplication(sys.argv)
21
22class dummy_manager(object):
23    HELP_DIRECTORY_LOCATION = "html"
24    communicate = Communicate()
25    _parent = QtWidgets.QDialog()
26
27class AddMultEditorTest(unittest.TestCase):
28    """ Test the simple AddMultEditor dialog """
29    @patch.object(AddMultEditor, 'readModels')
30    def setUp(self, mock_list_models):
31        """ Create AddMultEditor dialog """
32
33        # mock models from plugin folder
34        mock_list_models.return_value = ['cylinder', 'rpa',
35                                         'core_shell_cylinder', 'sphere']
36
37        self.widget = AddMultEditor(dummy_manager())
38
39    def tearDown(self):
40        """ Destroy the GUI """
41
42        self.widget.close()
43        self.widget = None
44
45    def testDefaults(self):
46        """ Test the GUI in its default state """
47
48        self.assertIsInstance(self.widget, QtWidgets.QDialog)
49
50        self.assertEqual(self.widget.sizePolicy().verticalPolicy(), 0)
51        self.assertEqual(self.widget.sizePolicy().horizontalPolicy(), 5)
52
53        # Default title
54        self.assertEqual(self.widget.windowTitle(), "Easy Add/Multiply Editor")
55
56        # Default types
57        self.assertIsInstance(self.widget.cbOperator, QtWidgets.QComboBox)
58        self.assertIsInstance(self.widget.cbModel1, QtWidgets.QComboBox)
59        self.assertIsInstance(self.widget.cbModel2, QtWidgets.QComboBox)
60
61        # Modal window
62        self.assertFalse(self.widget.isModal())
63
64        # Checkbox not tristate, not checked
65        self.assertFalse(self.widget.chkOverwrite.isTristate())
66        self.assertFalse(self.widget.chkOverwrite.isChecked())
67
68        # Push buttons disabled
69        self.assertFalse(self.widget.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).isEnabled())
70
71        # Text of labels...
72        self.assertEqual(self.widget.chkOverwrite.text(),
73                         "Overwrite existing model")
74
75        # Allowed operators
76        self.assertListEqual([str(self.widget.cbOperator.itemText(i)) for i in
77                              range(self.widget.cbOperator.count())],
78                             ['+', '*'])
79
80        # Default operator
81        self.assertEqual(self.widget.cbOperator.currentText(), '+')
82
83        # checkbox unchecked
84        self.assertFalse(self.widget.chkOverwrite.isChecked())
85
86        # Default 'good_name' flag, name for plugin file and plugin dir
87        self.assertFalse(self.widget.good_name)
88        self.assertIsNone(self.widget.plugin_filename)
89
90        # default content of displayed equation (to create the new model)
91        self.assertEqual(self.widget.lblEquation.text(),
92                         "<html><head/><body><p>Plugin_model = "
93                         "scale_factor * (model_1 + model_2) + background"
94                         "</p></body></html>")
95
96        # Tooltips
97        self.assertEqual(self.widget.cbOperator.toolTip(),
98                         "Add: +\nMultiply: *")
99        self.assertEqual(self.widget.txtName.toolTip(),
100                         "Sum / Multiply model function name.")
101        self.widget.chkOverwrite.setChecked(True)
102
103        self.assertNotEqual(len(self.widget.chkOverwrite.toolTip()), 0)
104
105    def testOnModelComboboxes(self):
106        """ Test on Model1 and Model2 comboboxes """
107
108        # content of model_1 and model_2 comboboxes
109        # same content for the two comboboxes
110        self.assertEqual(self.widget.cbModel1.count(),
111                         self.widget.cbModel2.count())
112
113        self.assertEqual(self.widget.cbModel1.count(), 4)
114
115        # default of cbModel1 and cbModel2
116        self.assertEqual(self.widget.cbModel1.currentText(), 'sphere')
117        self.assertEqual(self.widget.cbModel2.currentText(), 'cylinder')
118
119    def testValidateName(self):
120        """ Test validity of output name (syntax only) """
121
122        # Invalid plugin name
123        self.widget.txtName.setText('+++')
124
125        state = self.widget.txtName.validator().validate(self.widget.txtName.text(), 0)[0]
126        self.assertEqual(state, QtGui.QValidator.Invalid)
127
128        # Valid new plugin name
129        self.widget.txtName.setText('cylinder_test_case')
130        state = \
131        self.widget.txtName.validator().validate(self.widget.txtName.text(),
132                                                 0)[0]
133        self.assertEqual(state, QtGui.QValidator.Acceptable)
134
135    def testOnApply(self):
136        """ Test onApply """
137
138        self.widget.txtName.setText("new_model")
139        self.widget.updateModels = MagicMock()
140
141        # make sure the flag is set correctly
142        self.widget.is_modified = True
143
144        # Mock self.write_new_model_to_file
145        self.widget.plugin_dir = tempfile.gettempdir()
146        self.widget.plugin_filename = \
147            os.path.join(self.widget.plugin_dir, 'new_model.py')
148
149        self.widget.write_new_mode_to_file = MagicMock()
150
151        # invoke the tested method
152        self.widget.onApply()
153
154        self.assertTrue(self.widget.write_new_mode_to_file.called_once_with(
155        os.path.join(self.widget.plugin_dir, 'new_model.py'),
156        self.widget.cbModel1.currentText(),
157        self.widget.cbModel2.currentText(),
158        self.widget.cbOperator.currentText()))
159
160        self.assertTrue(self.widget.updateModels.called_once())
161
162    def testWriteNewModelToFile(self):
163        """ Test content of generated plugin"""
164
165        dummy_file_path = os.path.join(tempfile.gettempdir(),
166                                       "test_datafile.py")
167
168        # prepare data to create file and check its content: names of 2 models,
169        # operator and description (default or not)
170        model1_name = self.widget.cbModel1.currentText()
171        model2_name = self.widget.cbModel2.currentText()
172        symbol_operator = self.widget.cbOperator.currentText()
173
174        # default description
175        desc_line = "{} {} {}".format(model1_name,
176                                      symbol_operator,
177                                      model2_name)
178
179        self.widget.write_new_model_to_file(dummy_file_path, model1_name,
180                                            model2_name, symbol_operator)
181        # check content of dummy file path
182        with open(dummy_file_path, 'r') as f_in:
183            lines_from_generated_file = [line.strip() for line in f_in]
184
185        # SUM_TEMPLATE with updated entries
186        completed_template = ["from sasmodels.core import load_model_info",
187                        "from sasmodels.sasview_model import make_model_from_info",
188                        "model_info = load_model_info('{model1}{operator}{model2}')".
189                            format(model1=model1_name,
190                                   operator=symbol_operator,
191                                   model2=model2_name),
192                        "model_info.name = '{}'".format("test_datafile"),
193                        "model_info.description = '{}'".format(desc_line),
194                        "Model = make_model_from_info(model_info)"]
195
196        for item in completed_template:
197            self.assertIn(item, lines_from_generated_file)
198
199        # check content with description entered by user
200        self.widget.txtDescription.setText('New description for test  ')
201
202        new_desc_line = "model_info.description = '{}'".format('New description for test')
203
204        # re-run function to test
205        self.widget.write_new_model_to_file(dummy_file_path, model1_name,
206                                            model2_name, symbol_operator)
207
208        # check content of dummy file path
209        with open(dummy_file_path, 'r') as f_in:
210            lines_from_generated_file = [line.strip() for line in f_in]
211
212        # update completed template
213        completed_template[4] = new_desc_line
214
215        # check content of generated file
216        for item in completed_template:
217            self.assertIn(item, lines_from_generated_file)
218
219    def testOnOperatorChange(self):
220        """
221        Test modification of displayed equation
222        when selected operator is changed
223        """
224
225        # check default
226        self.assertIn(self.widget.cbOperator.currentText(),
227                      self.widget.lblEquation.text())
228
229        # change operator
230        if self.widget.cbOperator.currentIndex() == 0:
231            self.widget.cbOperator.setCurrentIndex(1)
232        else:
233            self.widget.cbOperator.setCurrentIndex(0)
234
235        self.assertIn(self.widget.cbOperator.currentText(),
236                      self.widget.lblEquation.text())
237
238    def testOnHelp(self):
239        """ Test the default help renderer """
240
241        webbrowser.open = MagicMock()
242
243        # invoke the tested method
244        self.widget.onHelp()
245
246        # see that webbrowser open was attempted
247        webbrowser.open.assert_called()
248
249    def testOnNameCheck(self):
250        """ Test onNameCheck """
251
252        # Enter plugin name already present in list of existing models
253        self.widget.txtName.setText("cylinder")
254
255        # Scenario 1
256        # overwrite not checked -> message box should appear
257        # and good_name set to False, 'Apply' button disabled
258
259        # mock QMessageBox
260        QtWidgets.QMessageBox.critical = MagicMock()
261
262        self.widget.chkOverwrite.setChecked(False)
263        self.widget.txtName.editingFinished.emit()
264        self.assertFalse(self.widget.good_name)
265        self.assertFalse(self.widget.buttonBox.button(
266            QtWidgets.QDialogButtonBox.Apply).isEnabled())
267
268        self.assertTrue(QtWidgets.QMessageBox.critical.called_once())
269
270        msg = "Plugin with specified name already exists.\n"
271        msg += "Please specify different filename or allow file overwrite."
272
273        self.assertIn('Plugin Error', QtWidgets.QMessageBox.critical.call_args[0][1])
274        self.assertIn(msg, QtWidgets.QMessageBox.critical.call_args[0][2])
275
276        # Scenario 2
277        # overwrite checked -> no message box displayed
278        # and good_name set to True, Apply button enabled, output name created
279
280        # mock QMessageBox
281        QtWidgets.QMessageBox.critical = MagicMock()
282        # create dummy plugin_dir for output file
283        self.widget.plugin_dir = tempfile.gettempdir()
284
285        self.widget.chkOverwrite.setChecked(True)
286        self.widget.txtName.editingFinished.emit()
287        self.assertTrue(self.widget.good_name)
288        self.assertTrue(self.widget.buttonBox.button(
289            QtWidgets.QDialogButtonBox.Apply).isEnabled())
290
291        self.assertFalse(QtWidgets.QMessageBox.critical.called)
292
293        self.assertIn('cylinder.py', self.widget.plugin_filename)
294
295        # Scenario 3 Enter valid new plugin name -> filename created and Apply
296        # button enabled
297        # forbidding overwriting should not change anything
298        # since it's a new name
299        self.widget.txtName.setText("   cylinder0   ")
300        self.widget.chkOverwrite.setChecked(False)
301        self.widget.txtName.editingFinished.emit()
302        self.assertIn("cylinder0.py", self.widget.plugin_filename)
303        self.assertTrue(self.widget.buttonBox.button(
304            QtWidgets.QDialogButtonBox.Apply).isEnabled())
305
306    @patch.object(AddMultEditor, 'readModels')
307    def testOnUpdateModels(self, mock_new_list_models):
308        """ Test onUpdateModels """
309
310        ini_count_models = self.widget.cbModel1.count()
311
312        mock_new_list_models.return_value = ['cylinder', 'rpa',
313                                             'core_shell_cylinder', 'sphere',
314                                             'cylinder0']
315
316        self.widget.updateModels()
317        # check that the number of models in the comboboxes
318        # has been incremented by 1
319        self.assertEqual(self.widget.cbModel1.count(), ini_count_models + 1)
320        self.assertEqual(self.widget.cbModel2.count(), ini_count_models + 1)
321
322        # check that the new model is in the list
323        combobox = self.widget.cbModel1
324        self.assertIn('cylinder0', [combobox.itemText(indx)
325                                    for indx in range(combobox.count())])
326
327    def testOnReadModels(self):
328        """ The output of ReadModels is the return value of MagicMock defined
329        in the SetUp of these tests. """
330
331        self.assertEqual(self.widget.list_models, ['cylinder', 'rpa',
332                                                   'core_shell_cylinder',
333                                                   'sphere'])
334
335    def testCheckModel(self):
336        """ Test CheckModel"""
337
338        # TODO first: solve problem with empty 'test'
339        pass
Note: See TracBrowser for help on using the repository browser.