source: sasview/src/sas/qtgui/Utilities/UnitTesting/GuiUtilsTest.py @ c6fb57c

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

Added unit tests for recent functionality

  • Property mode set to 100644
File size: 18.7 KB
Line 
1import sys
2import unittest
3import webbrowser
4
5from PyQt5 import QtCore
6from PyQt5 import QtGui, QtWidgets
7from unittest.mock import MagicMock
8
9# set up import paths
10import sas.qtgui.path_prepare
11
12# SV imports
13from sas.sascalc.dataloader.loader import Loader
14from sas.qtgui.MainWindow.DataManager import DataManager
15from sas.qtgui.Plotting.PlotterData import Data1D
16from sas.qtgui.Plotting.PlotterData import Data2D
17
18# Tested module
19from sas.qtgui.Utilities.GuiUtils import *
20
21if not QtWidgets.QApplication.instance():
22    app = QtWidgets.QApplication(sys.argv)
23
24class GuiUtilsTest(unittest.TestCase):
25    '''Test the GUI Utilities methods'''
26    def setUp(self):
27        '''Empty'''
28        pass
29
30    def tearDown(self):
31        '''Empty'''
32        pass
33
34    def testDefaults(self):
35        """
36        Test all the global constants defined in the file.
37        """
38        # Should probably test the constants in the file,
39        # but this will done after trimming down GuiUtils
40        # and retaining only necessary variables.
41        pass
42
43    def testGetAppDir(self):
44        """
45        """
46        pass
47
48    def testGetUserDirectory(self):
49        """
50        Simple test of user directory getter
51        """
52        home_dir = os.path.expanduser("~")
53        self.assertIn(home_dir, get_user_directory())
54
55    def testCommunicate(self):
56        """
57        Test the container class with signal definitions
58        """
59        com = Communicate()
60
61        # All defined signals
62        list_of_signals = [
63            'fileReadSignal',
64            'fileDataReceivedSignal',
65            'statusBarUpdateSignal',
66            'updatePerspectiveWithDataSignal',
67            'updateModelFromPerspectiveSignal',
68            'plotRequestedSignal',
69            'progressBarUpdateSignal',
70            'activeGraphName',
71            'sendDataToPanelSignal',
72            'updateModelFromDataOperationPanelSignal'
73        ]
74
75        # Assure all signals are defined.
76        for signal in list_of_signals:
77            self.assertIn(signal, dir(com))
78
79    def testupdateModelItem(self):
80        """
81        Test the generic QModelItem update method
82        """
83        test_item = QtGui.QStandardItem()
84        test_list = ['aa', 4, True, ]
85        name = "Black Sabbath"
86
87        # update the item
88        updateModelItem(test_item, test_list, name)
89
90        # Make sure test_item got all data added
91        self.assertEqual(test_item.child(0).text(), name)
92        list_from_item = test_item.child(0).data()
93        self.assertIsInstance(list_from_item, list)
94        self.assertEqual(list_from_item[0], test_list[0])
95        self.assertEqual(list_from_item[1], test_list[1])
96        self.assertEqual(list_from_item[2], test_list[2])
97
98    def testupdateModelItemWithPlot(self):
99        """
100        Test the QModelItem checkbox update method
101        """
102        test_item = QtGui.QStandardItem()
103        test_list = ['aa','11']
104        update_data = test_list
105        name = "Black Sabbath"
106
107        # update the item
108        updateModelItemWithPlot(test_item, update_data, name)
109       
110        # Make sure test_item got all data added
111        self.assertEqual(test_item.child(0).text(), name)
112        self.assertTrue(test_item.child(0).isCheckable())
113        list_from_item = test_item.child(0).child(0).data()
114        self.assertIsInstance(list_from_item, list)
115        self.assertEqual(str(list_from_item[0]), test_list[0])
116        self.assertEqual(str(list_from_item[1]), test_list[1])
117
118
119    def testPlotsFromCheckedItems(self):
120        """
121        Test addition of a plottable to the model
122        """
123
124        # Mockup data
125        test_list0 = "FRIDAY"
126        test_list1 = "SATURDAY"
127        test_list2 = "MONDAY"
128
129        # Main item ("file")
130        checkbox_model = QtGui.QStandardItemModel()
131        checkbox_item = QtGui.QStandardItem(True)
132        checkbox_item.setCheckable(True)
133        checkbox_item.setCheckState(QtCore.Qt.Checked)
134        test_item0 = QtGui.QStandardItem()
135        test_item0.setData(test_list0)
136
137        # Checked item 1
138        test_item1 = QtGui.QStandardItem(True)
139        test_item1.setCheckable(True)
140        test_item1.setCheckState(QtCore.Qt.Checked)
141        object_item = QtGui.QStandardItem()
142        object_item.setData(test_list1)
143        test_item1.setChild(0, object_item)
144
145        checkbox_item.setChild(0, test_item0)
146        checkbox_item.appendRow(test_item1)
147
148        # Unchecked item 2
149        test_item2 = QtGui.QStandardItem(True)
150        test_item2.setCheckable(True)
151        test_item2.setCheckState(QtCore.Qt.Unchecked)
152        object_item = QtGui.QStandardItem()
153        object_item.setData(test_list2)
154        test_item2.setChild(0, object_item)
155        checkbox_item.appendRow(test_item2)
156
157        checkbox_model.appendRow(checkbox_item)
158
159        # Pull out the "plottable" documents
160        plot_list = plotsFromCheckedItems(checkbox_model)
161
162        # Make sure only the checked data is present
163        # FRIDAY IN
164        self.assertIn(test_list0, plot_list[0])
165        # SATURDAY IN
166        self.assertIn(test_list1, plot_list[1])
167        # MONDAY NOT IN
168        self.assertNotIn(test_list2, plot_list[0])
169        self.assertNotIn(test_list2, plot_list[1])
170
171    def testInfoFromData(self):
172        """
173        Test Info element extraction from a plottable object
174        """
175        loader = Loader()
176        manager = DataManager()
177
178        # get Data1D
179        p_file="cyl_400_20.txt"
180        output_object = loader.load(p_file)
181        new_data = manager.create_gui_data(output_object[0], p_file)
182
183        # Extract Info elements into a model item
184        item = infoFromData(new_data)
185
186        # Test the item and its children
187        self.assertIsInstance(item, QtGui.QStandardItem)
188        self.assertEqual(item.rowCount(), 5)
189        self.assertEqual(item.text(), "Info")
190        self.assertIn(p_file,   item.child(0).text())
191        self.assertIn("Run",    item.child(1).text())
192        self.assertIn("Data1D", item.child(2).text())
193        self.assertIn(p_file,   item.child(3).text())
194        self.assertIn("Process",item.child(4).text())
195
196    def testOpenLink(self):
197        """
198        Opening a link in the external browser
199        """
200        good_url1 = r"http://test.test.com"
201        good_url2 = r"mailto:test@mail.com"
202        good_url3 = r"https://127.0.0.1"
203
204        bad_url1 = ""
205        bad_url2 = QtGui.QStandardItem()
206        bad_url3 = r"poop;//**I.am.a.!bad@url"
207
208        webbrowser.open = MagicMock()
209        openLink(good_url1)
210        openLink(good_url2)
211        openLink(good_url3)
212        self.assertEqual(webbrowser.open.call_count, 3)
213
214        with self.assertRaises(AttributeError):
215            openLink(bad_url1)
216        with self.assertRaises(AttributeError):
217            openLink(bad_url2)
218        with self.assertRaises(AttributeError):
219            openLink(bad_url3)
220
221    def testRetrieveData1d(self):
222        """
223        """
224        with self.assertRaises(AttributeError):
225            retrieveData1d("BOOP")
226
227        #data = Data1D()
228        #with self.assertRaises(ValueError):
229        #    retrieveData1d(data)
230
231        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0])
232
233        text = retrieveData1d(data)
234
235        self.assertIn("Temperature:", text)
236        self.assertIn("Beam_size:", text)
237        self.assertIn("X_min = 1.0:  X_max = 3.0", text)
238        self.assertIn("3.0 \t12.0 \t0.0 \t0.0", text)
239
240    def testRetrieveData2d(self):
241        """
242        """
243        with self.assertRaises(AttributeError):
244            retrieveData2d("BOOP")
245        data = Data2D(image=[1.0, 2.0, 3.0],
246                      err_image=[0.01, 0.02, 0.03],
247                      qx_data=[0.1, 0.2, 0.3],
248                      qy_data=[0.1, 0.2, 0.3])
249
250        text = retrieveData2d(data)
251
252        self.assertIn("Type:         Data2D", text)
253        self.assertIn("I_min = 1.0", text)
254        self.assertIn("I_max = 3.0", text)
255        self.assertIn("2 \t0.3 \t0.3 \t3.0 \t0.03 \t0.0 \t0.0", text)
256
257    def testOnTXTSave(self):
258        """
259        Test the file writer for saving 1d/2d data
260        """
261        path = "test123"
262        if os.path.isfile(path):
263            os.remove(path)
264
265        # Broken data
266        data = Data1D(x=[1.0, 2.0, 3.0], y=[])
267        # Expect a raise
268        with self.assertRaises(IndexError):
269            onTXTSave(data, path)
270
271        # Good data - no dX/dY
272        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0])
273        onTXTSave(data, path)
274
275        self.assertTrue(os.path.isfile(path))
276        with open(path,'r') as out:
277            data_read = out.read()
278            self.assertEqual("<X>   <Y>\n1  10\n2  11\n3  12\n", data_read)
279
280        if os.path.isfile(path):
281            os.remove(path)
282
283        # Good data - with dX/dY
284        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
285                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
286
287        onTXTSave(data, path)
288        with open(path,'r') as out:
289            data_read = out.read()
290            self.assertIn("<X>   <Y>   <dY>   <dX>\n", data_read)
291            self.assertIn("1  10  0.1  0.1\n", data_read)
292            self.assertIn("2  11  0.2  0.2\n", data_read)
293            self.assertIn("3  12  0.3  0.3\n", data_read)
294
295        if os.path.isfile(path):
296            os.remove(path)
297
298    def testSaveData1D(self):
299        """
300        Test the 1D file save method
301        """
302        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
303                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
304
305        # Test the .txt format
306        file_name = "test123_out.txt"
307        QtWidgets.QFileDialog.getSaveFileName = MagicMock(return_value=(file_name,''))
308        data.filename = "test123.txt"
309        saveData1D(data)
310        self.assertTrue(os.path.isfile(file_name))
311        os.remove(file_name)
312
313        # Test the .xml format
314        file_name = "test123_out.xml"
315        QtWidgets.QFileDialog.getSaveFileName = MagicMock(return_value=(file_name,''))
316        data.filename = "test123.xml"
317        saveData1D(data)
318        self.assertTrue(os.path.isfile(file_name))
319        os.remove(file_name)
320
321        # Test the wrong format
322        file_name = "test123_out.mp3"
323        QtWidgets.QFileDialog.getSaveFileName = MagicMock(return_value=(file_name,''))
324        data.filename = "test123.mp3"
325        saveData1D(data)
326        self.assertFalse(os.path.isfile(file_name))
327
328    def testSaveData2D(self):
329        """
330        Test the 1D file save method
331        """
332        data = Data2D(image=[1.0, 2.0, 3.0],
333                      err_image=[0.01, 0.02, 0.03],
334                      qx_data=[0.1, 0.2, 0.3],
335                      qy_data=[0.1, 0.2, 0.3])
336
337        # Test the .txt format
338        file_name = "test123_out.dat"
339        QtWidgets.QFileDialog.getSaveFileName = MagicMock(return_value=(file_name,''))
340        data.filename = "test123.dat"
341        saveData2D(data)
342        self.assertTrue(os.path.isfile(file_name))
343        os.remove(file_name)
344
345        # Test the wrong format
346        file_name = "test123_out.mp3"
347        QtWidgets.QFileDialog.getSaveFileName = MagicMock(return_value=(file_name,''))
348        data.filename = "test123.mp3"
349        saveData2D(data)
350        self.assertFalse(os.path.isfile(file_name))
351
352    def testXYTransform(self):
353        """ Assure the unit/legend transformation is correct"""
354        data = Data1D(x=[1.0, 2.0, 3.0], y=[10.0, 11.0, 12.0],
355                      dx=[0.1, 0.2, 0.3], dy=[0.1, 0.2, 0.3])
356
357        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="y")
358        self.assertEqual(xLabel, "()")
359        self.assertEqual(xscale, "linear")
360        self.assertEqual(yscale, "linear")
361
362        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x^(2)", yLabel="1/y")
363        self.assertEqual(xLabel, "^{2}(()^{2})")
364        self.assertEqual(yLabel, "1/(()^{-1})")
365        self.assertEqual(xscale, "linear")
366        self.assertEqual(yscale, "linear")
367
368        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x^(4)", yLabel="ln(y)")
369        self.assertEqual(xLabel, "^{4}(()^{4})")
370        self.assertEqual(yLabel, "\\ln{()}()")
371        self.assertEqual(xscale, "linear")
372        self.assertEqual(yscale, "linear")
373
374        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="ln(x)", yLabel="y^(2)")
375        self.assertEqual(xLabel, "\\ln{()}()")
376        self.assertEqual(yLabel, "^{2}(()^{2})")
377        self.assertEqual(xscale, "linear")
378        self.assertEqual(yscale, "linear")
379
380        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="log10(x)", yLabel="y*x^(2)")
381        self.assertEqual(xLabel, "()")
382        self.assertEqual(yLabel, " \\ \\ ^{2}(()^{2})")
383        self.assertEqual(xscale, "log")
384        self.assertEqual(yscale, "linear")
385
386        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="log10(x^(4))", yLabel="y*x^(4)")
387        self.assertEqual(xLabel, "^{4}(()^{4})")
388        self.assertEqual(yLabel, " \\ \\ ^{4}(()^{16})")
389        self.assertEqual(xscale, "log")
390        self.assertEqual(yscale, "linear")
391
392        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="1/sqrt(y)")
393        self.assertEqual(yLabel, "1/\\sqrt{}(()^{-0.5})")
394        self.assertEqual(yscale, "linear")
395
396        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="log10(y)")
397        self.assertEqual(yLabel, "()")
398        self.assertEqual(yscale, "log")
399
400        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x)")
401        self.assertEqual(yLabel, "\\ln{( \\ \\ )}()")
402        self.assertEqual(yscale, "linear")
403
404        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x^(2))")
405        self.assertEqual(yLabel, "\\ln ( \\ \\ ^{2})(()^{2})")
406        self.assertEqual(yscale, "linear")
407
408        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="ln(y*x^(4))")
409        self.assertEqual(yLabel, "\\ln ( \\ \\ ^{4})(()^{4})")
410        self.assertEqual(yscale, "linear")
411
412        xLabel, yLabel, xscale, yscale = xyTransform(data, xLabel="x", yLabel="log10(y*x^(4))")
413        self.assertEqual(yLabel, " \\ \\ ^{4}(()^{4})")
414        self.assertEqual(yscale, "log")
415
416    def testParseName(self):
417        '''test parse out a string from the beinning of a string'''
418        # good input
419        value = "_test"
420        self.assertEqual(parseName(value, '_'), 'test')
421        value = "____test____"
422        self.assertEqual(parseName(value, '_'), '___test____')
423        self.assertEqual(parseName(value, '___'), '_test____')
424        self.assertEqual(parseName(value, 'test'), '____test____')
425        # bad input
426        with self.assertRaises(TypeError):
427            parseName(value, None)
428        with self.assertRaises(TypeError):
429            parseName(None, '_')
430        value = []
431        with self.assertRaises(TypeError):
432            parseName(value, '_')
433        value = 1.44
434        with self.assertRaises(TypeError):
435            parseName(value, 'p')
436        value = 100
437        with self.assertRaises(TypeError):
438            parseName(value, 'p')
439
440    def testToDouble(self):
441        '''test homemade string-> double converter'''
442        #good values
443        value = "1"
444        self.assertEqual(toDouble(value), 1.0)
445        value = "1.2"
446        # has to be AlmostEqual due to numerical rounding
447        self.assertAlmostEqual(toDouble(value), 1.2, 6)
448        value = "2,1"
449        self.assertAlmostEqual(toDouble(value), 2.1, 6)
450
451        # bad values
452        value = None
453        with self.assertRaises(TypeError):
454            toDouble(value)
455        value = "MyDouble"
456        with self.assertRaises(TypeError):
457            toDouble(value)
458        value = [1,2.2]
459        with self.assertRaises(TypeError):
460            toDouble(value)
461
462
463class DoubleValidatorTest(unittest.TestCase):
464    """ Test the validator for floats """
465    def setUp(self):
466        '''Create the validator'''
467        self.validator = DoubleValidator()
468
469    def tearDown(self):
470        '''Destroy the validator'''
471        self.validator = None
472
473    def testValidateGood(self):
474        """Test a valid float """
475        QtCore.QLocale.setDefault(QtCore.QLocale('en_US'))
476        float_good = "170"
477        self.assertEqual(self.validator.validate(float_good, 1)[0], QtGui.QValidator.Acceptable)
478        float_good = "170.11"
479        ## investigate: a double returns Invalid here!
480        ##self.assertEqual(self.validator.validate(float_good, 1)[0], QtGui.QValidator.Acceptable)
481        float_good = "17e2"
482        self.assertEqual(self.validator.validate(float_good, 1)[0], QtGui.QValidator.Acceptable)
483
484    def testValidateBad(self):
485        """Test a bad float """
486        float_bad = None
487        self.assertEqual(self.validator.validate(float_bad, 1)[0], QtGui.QValidator.Intermediate)
488        float_bad = [1]
489        with self.assertRaises(TypeError):
490           self.validator.validate(float_bad, 1)
491        float_bad = "1,3"
492        self.assertEqual(self.validator.validate(float_bad, 1)[0], QtGui.QValidator.Invalid)
493
494    def notestFixup(self):
495        """Fixup of a float"""
496        float_to_fixup = "1,3"
497        self.validator.fixup(float_to_fixup)
498        self.assertEqual(float_to_fixup, "13")
499
500
501class FormulaValidatorTest(unittest.TestCase):
502    """ Test the formula validator """
503    def setUp(self):
504        '''Create the validator'''
505        self.validator = FormulaValidator()
506
507    def tearDown(self):
508        '''Destroy the validator'''
509        self.validator = None
510
511    def testValidateGood(self):
512        """Test a valid Formula """
513        formula_good = "H24O12C4C6N2Pu"
514        self.assertEqual(self.validator.validate(formula_good, 1)[0], QtGui.QValidator.Acceptable)
515
516        formula_good = "(H2O)0.5(D2O)0.5"
517        self.assertEqual(self.validator.validate(formula_good, 1)[0], QtGui.QValidator.Acceptable)
518
519    def testValidateBad(self):
520        """Test an invalid Formula """
521        formula_bad = "H24 %%%O12C4C6N2Pu"
522        self.assertRaises(self.validator.validate(formula_bad, 1)[0])
523        self.assertEqual(self.validator.validate(formula_bad, 1)[0], QtGui.QValidator.Intermediate)
524
525        formula_bad = [1]
526        self.assertEqual(self.validator.validate(formula_bad, 1)[0], QtGui.QValidator.Intermediate)
527
528class HashableStandardItemTest(unittest.TestCase):
529    """ Test the reimplementation of QStandardItem """
530    def setUp(self):
531        '''Create the validator'''
532        self.item = HashableStandardItem()
533
534    def tearDown(self):
535        '''Destroy the validator'''
536        self.item = None
537
538    def testHash(self):
539        '''assure the item returns hash'''
540        self.assertEqual(self.item.__hash__(), 0)
541
542    def testIndexing(self):
543        '''test that we can use HashableSI as an index'''
544        dictionary = {}
545        dictionary[self.item] = "wow!"
546        self.assertEqual(dictionary[self.item], "wow!")
547
548    def testClone(self):
549        '''let's see if we can clone the item'''
550        item_clone = self.item.clone()
551        self.assertEqual(item_clone.__hash__(), 0)
552
553if __name__ == "__main__":
554    unittest.main()
555
Note: See TracBrowser for help on using the repository browser.