diff options
Diffstat (limited to 'src/silx/app/view/test/test_view.py')
-rw-r--r-- | src/silx/app/view/test/test_view.py | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/src/silx/app/view/test/test_view.py b/src/silx/app/view/test/test_view.py new file mode 100644 index 0000000..e236e42 --- /dev/null +++ b/src/silx/app/view/test/test_view.py @@ -0,0 +1,388 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2016-2020 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ +"""Module testing silx.app.view""" + +__authors__ = ["V. Valls"] +__license__ = "MIT" +__date__ = "07/06/2018" + + +import weakref +import numpy +import h5py +import pytest + +from silx.gui import qt +from silx.app.view.Viewer import Viewer +from silx.app.view.About import About +from silx.app.view.DataPanel import DataPanel +from silx.app.view.CustomNxdataWidget import CustomNxdataWidget +from silx.gui.hdf5._utils import Hdf5DatasetMimeData +from silx.gui.utils.testutils import TestCaseQt +from silx.io import commonh5 + + +@pytest.fixture(scope="module") +def data_h5(tmpdir_factory): + filename = tmpdir_factory.mktemp("data").join("data.h5") + filename = str(filename) + f = h5py.File(filename, "w") + g = f.create_group("arrays") + g.create_dataset("scalar", data=10) + g.create_dataset("integers", data=numpy.array([10, 20, 30])) + f.close() + return filename + + +@pytest.fixture(scope="module") +def data2_h5(tmpdir_factory): + filename = tmpdir_factory.mktemp("data").join("data2.h5") + filename = str(filename) + f = h5py.File(filename, "w") + g = f.create_group("arrays") + g.create_dataset("scalar", data=20) + g.create_dataset("integers", data=numpy.array([10, 20, 30])) + f.close() + return filename + + +@pytest.fixture(scope="class") +def data_class_attr(request, data_h5, data2_h5): + """Provides test_options as class attribute + + Used as transition from TestCase to pytest + """ + request.cls.data_h5 = data_h5 + request.cls.data2_h5 = data2_h5 + + +@pytest.mark.usefixtures("qapp") +class TestViewer(TestCaseQt): + """Test for Viewer class""" + + def testConstruct(self): + widget = Viewer() + self.qWaitForWindowExposed(widget) + + def testDestroy(self): + widget = Viewer() + ref = weakref.ref(widget) + widget = None + self.qWaitForDestroy(ref) + + +@pytest.mark.usefixtures("qapp") +class TestAbout(TestCaseQt): + """Test for About box class""" + + def testConstruct(self): + widget = About() + self.qWaitForWindowExposed(widget) + + def testLicense(self): + widget = About() + widget.getHtmlLicense() + self.qWaitForWindowExposed(widget) + + def testDestroy(self): + widget = About() + ref = weakref.ref(widget) + widget = None + self.qWaitForDestroy(ref) + + +@pytest.mark.usefixtures("qapp") +@pytest.mark.usefixtures("data_class_attr") +class TestDataPanel(TestCaseQt): + + def testConstruct(self): + widget = DataPanel() + self.qWaitForWindowExposed(widget) + + def testDestroy(self): + widget = DataPanel() + ref = weakref.ref(widget) + widget = None + self.qWaitForDestroy(ref) + + def testHeaderLabelPaintEvent(self): + widget = DataPanel() + data = numpy.array([1, 2, 3, 4, 5]) + widget.setData(data) + # Expected to execute HeaderLabel.paintEvent + widget.setVisible(True) + self.qWaitForWindowExposed(widget) + + def testData(self): + widget = DataPanel() + data = numpy.array([1, 2, 3, 4, 5]) + widget.setData(data) + self.assertIs(widget.getData(), data) + self.assertIs(widget.getCustomNxdataItem(), None) + + def testDataNone(self): + widget = DataPanel() + widget.setData(None) + self.assertIs(widget.getData(), None) + self.assertIs(widget.getCustomNxdataItem(), None) + + def testCustomDataItem(self): + class CustomDataItemMock(object): + def getVirtualGroup(self): + return None + + def text(self): + return "" + + data = CustomDataItemMock() + widget = DataPanel() + widget.setCustomDataItem(data) + self.assertIs(widget.getData(), None) + self.assertIs(widget.getCustomNxdataItem(), data) + + def testCustomDataItemNone(self): + data = None + widget = DataPanel() + widget.setCustomDataItem(data) + self.assertIs(widget.getData(), None) + self.assertIs(widget.getCustomNxdataItem(), data) + + def testRemoveDatasetsFrom(self): + f = h5py.File(self.data_h5, mode='r') + try: + widget = DataPanel() + widget.setData(f["arrays/scalar"]) + widget.removeDatasetsFrom(f) + self.assertIs(widget.getData(), None) + finally: + widget.setData(None) + f.close() + + def testReplaceDatasetsFrom(self): + f = h5py.File(self.data_h5, mode='r') + f2 = h5py.File(self.data2_h5, mode='r') + try: + widget = DataPanel() + widget.setData(f["arrays/scalar"]) + self.assertEqual(widget.getData()[()], 10) + widget.replaceDatasetsFrom(f, f2) + self.assertEqual(widget.getData()[()], 20) + finally: + widget.setData(None) + f.close() + f2.close() + + +@pytest.mark.usefixtures("qapp") +@pytest.mark.usefixtures("data_class_attr") +class TestCustomNxdataWidget(TestCaseQt): + + def testConstruct(self): + widget = CustomNxdataWidget() + self.qWaitForWindowExposed(widget) + + def testDestroy(self): + widget = CustomNxdataWidget() + ref = weakref.ref(widget) + widget = None + self.qWaitForDestroy(ref) + + def testCreateNxdata(self): + widget = CustomNxdataWidget() + model = widget.model() + model.createNewNxdata() + model.createNewNxdata("Foo") + widget.setVisible(True) + self.qWaitForWindowExposed(widget) + + def testCreateNxdataFromDataset(self): + widget = CustomNxdataWidget() + model = widget.model() + signal = commonh5.Dataset("foo", data=numpy.array([[[5]]])) + model.createFromSignal(signal) + widget.setVisible(True) + self.qWaitForWindowExposed(widget) + + def testCreateNxdataFromNxdata(self): + widget = CustomNxdataWidget() + model = widget.model() + data = numpy.array([[[5]]]) + nxdata = commonh5.Group("foo") + nxdata.attrs["NX_class"] = "NXdata" + nxdata.attrs["signal"] = "signal" + nxdata.create_dataset("signal", data=data) + model.createFromNxdata(nxdata) + widget.setVisible(True) + self.qWaitForWindowExposed(widget) + + def testCreateBadNxdata(self): + widget = CustomNxdataWidget() + model = widget.model() + signal = commonh5.Dataset("foo", data=numpy.array([[[5]]])) + model.createFromSignal(signal) + axis = commonh5.Dataset("foo", data=numpy.array([[[5]]])) + nxdataIndex = model.index(0, 0) + item = model.itemFromIndex(nxdataIndex) + item.setAxesDatasets([axis]) + nxdata = item.getVirtualGroup() + self.assertIsNotNone(nxdata) + self.assertFalse(item.isValid()) + + def testRemoveDatasetsFrom(self): + f = h5py.File(self.data_h5, mode='r') + try: + widget = CustomNxdataWidget() + model = widget.model() + dataset = f["arrays/integers"] + model.createFromSignal(dataset) + widget.removeDatasetsFrom(f) + finally: + model.clear() + f.close() + + def testReplaceDatasetsFrom(self): + f = h5py.File(self.data_h5, mode='r') + f2 = h5py.File(self.data2_h5, mode='r') + try: + widget = CustomNxdataWidget() + model = widget.model() + dataset = f["arrays/integers"] + model.createFromSignal(dataset) + widget.replaceDatasetsFrom(f, f2) + finally: + model.clear() + f.close() + f2.close() + + +@pytest.mark.usefixtures("qapp") +class TestCustomNxdataWidgetInteraction(TestCaseQt): + """Test CustomNxdataWidget with user interaction""" + + def setUp(self): + TestCaseQt.setUp(self) + + self.widget = CustomNxdataWidget() + self.model = self.widget.model() + data = numpy.array([[[5]]]) + dataset = commonh5.Dataset("foo", data=data) + self.model.createFromSignal(dataset) + self.selectionModel = self.widget.selectionModel() + + def tearDown(self): + self.selectionModel = None + self.model.clear() + self.model = None + self.widget = None + TestCaseQt.tearDown(self) + + def testSelectedNxdata(self): + index = self.model.index(0, 0) + self.selectionModel.setCurrentIndex(index, qt.QItemSelectionModel.ClearAndSelect) + nxdata = self.widget.selectedNxdata() + self.assertEqual(len(nxdata), 1) + self.assertIsNot(nxdata[0], None) + + def testSelectedItems(self): + index = self.model.index(0, 0) + self.selectionModel.setCurrentIndex(index, qt.QItemSelectionModel.ClearAndSelect) + items = self.widget.selectedItems() + self.assertEqual(len(items), 1) + self.assertIsNot(items[0], None) + self.assertIsInstance(items[0], qt.QStandardItem) + + def testRowsAboutToBeRemoved(self): + self.model.removeRow(0) + self.qWaitForWindowExposed(self.widget) + + def testPaintItems(self): + self.widget.expandAll() + self.widget.setVisible(True) + self.qWaitForWindowExposed(self.widget) + + def testCreateDefaultContextMenu(self): + nxDataIndex = self.model.index(0, 0) + menu = self.widget.createDefaultContextMenu(nxDataIndex) + self.assertIsNot(menu, None) + self.assertIsInstance(menu, qt.QMenu) + + signalIndex = self.model.index(0, 0, nxDataIndex) + menu = self.widget.createDefaultContextMenu(signalIndex) + self.assertIsNot(menu, None) + self.assertIsInstance(menu, qt.QMenu) + + axesIndex = self.model.index(1, 0, nxDataIndex) + menu = self.widget.createDefaultContextMenu(axesIndex) + self.assertIsNot(menu, None) + self.assertIsInstance(menu, qt.QMenu) + + def testDropNewDataset(self): + dataset = commonh5.Dataset("foo", numpy.array([1, 2, 3, 4])) + mimedata = Hdf5DatasetMimeData(dataset=dataset) + self.model.dropMimeData(mimedata, qt.Qt.CopyAction, -1, -1, qt.QModelIndex()) + self.assertEqual(self.model.rowCount(qt.QModelIndex()), 2) + + def testDropNewNxdata(self): + data = numpy.array([[[5]]]) + nxdata = commonh5.Group("foo") + nxdata.attrs["NX_class"] = "NXdata" + nxdata.attrs["signal"] = "signal" + nxdata.create_dataset("signal", data=data) + mimedata = Hdf5DatasetMimeData(dataset=nxdata) + self.model.dropMimeData(mimedata, qt.Qt.CopyAction, -1, -1, qt.QModelIndex()) + self.assertEqual(self.model.rowCount(qt.QModelIndex()), 2) + + def testDropAxisDataset(self): + dataset = commonh5.Dataset("foo", numpy.array([1, 2, 3, 4])) + mimedata = Hdf5DatasetMimeData(dataset=dataset) + nxDataIndex = self.model.index(0, 0) + axesIndex = self.model.index(1, 0, nxDataIndex) + self.model.dropMimeData(mimedata, qt.Qt.CopyAction, -1, -1, axesIndex) + self.assertEqual(self.model.rowCount(qt.QModelIndex()), 1) + item = self.model.itemFromIndex(axesIndex) + self.assertIsNot(item.getDataset(), None) + + def testMimeData(self): + nxDataIndex = self.model.index(0, 0) + signalIndex = self.model.index(0, 0, nxDataIndex) + mimeData = self.model.mimeData([signalIndex]) + self.assertIsNot(mimeData, None) + self.assertIsInstance(mimeData, qt.QMimeData) + + def testRemoveNxdataItem(self): + nxdataIndex = self.model.index(0, 0) + item = self.model.itemFromIndex(nxdataIndex) + self.model.removeNxdataItem(item) + + def testAppendAxisToNxdataItem(self): + nxdataIndex = self.model.index(0, 0) + item = self.model.itemFromIndex(nxdataIndex) + self.model.appendAxisToNxdataItem(item) + + def testRemoveAxisItem(self): + nxdataIndex = self.model.index(0, 0) + axesIndex = self.model.index(1, 0, nxdataIndex) + item = self.model.itemFromIndex(axesIndex) + self.model.removeAxisItem(item) |