From efdbc8e01b2e688327f42a5be3465dcceaeb0fde Mon Sep 17 00:00:00 2001 From: tov101 <82372114+tov101@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:37:08 +0300 Subject: [PATCH] Extend tests for FileWidget Context Menu (#924) Extend tests for FileWidget Context Menu --- src/asammdf/gui/widgets/tree.py | 2 +- test/asammdf/gui/resources/missingItems.dspf | 408 ++++++++++++++++ .../widgets/test_PlotWidget_ContextMenu.py | 448 +++++++++++++++++- .../widgets/test_PlotWidget_DragAndDrop.py | 1 + 4 files changed, 857 insertions(+), 2 deletions(-) create mode 100644 test/asammdf/gui/resources/missingItems.dspf diff --git a/src/asammdf/gui/widgets/tree.py b/src/asammdf/gui/widgets/tree.py index 2ea0775c0..7ebc4a301 100644 --- a/src/asammdf/gui/widgets/tree.py +++ b/src/asammdf/gui/widgets/tree.py @@ -1029,7 +1029,7 @@ def open_menu(self): for item in self.selectedItems(): if item.type() == ChannelsTreeItem.Channel: while True: - rgb = random.randbytes(3) + rgb = os.urandom(3) if 100 <= sum(rgb) <= 650: break diff --git a/test/asammdf/gui/resources/missingItems.dspf b/test/asammdf/gui/resources/missingItems.dspf new file mode 100644 index 000000000..af669eea2 --- /dev/null +++ b/test/asammdf/gui/resources/missingItems.dspf @@ -0,0 +1,408 @@ +{ + "selected_channels": [], + "windows": [ + { + "title": "Plot 0", + "configuration": { + "channels": [ + { + "type": "channel", + "name": "ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2", + "unit": "m/s", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#1f77b4", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + -256.0, + 254.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "1stMissingItem", + "unit": "", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#7975eb", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + -256.0, + 254.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.SLONG.IDENTICAL", + "unit": "hours", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#ff7f0e", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.0, + 999.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.SWORD.IDENTICAL", + "unit": "hours", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#2ca02c", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.0, + 999.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.FORM_X_PLUS_4", + "unit": "rpm", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#d62728", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + 4.0, + 259.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.HYPERBOLIC", + "unit": "km/h", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#c94597", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.00392156862745098, + 1.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.IDENTICAL", + "unit": "hours", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#8c564b", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.0, + 255.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.IDENTICAL.STATUS_STRING", + "unit": "m/s", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#e377c2", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.0, + 255.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.RAT_FUNC.DIV_10", + "unit": "km/h", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#7f7f7f", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.0, + 25.5 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.RAT_FUNC.IDENT.STATUS_STRING", + "unit": "m/s", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#bcbd22", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.0, + 255.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.TAB_INTP_DEFAULT_VALUE", + "unit": "U/ min", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#17becf", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + 100.0, + 111.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.TAB_INTP_NO_DEFAULT_VALUE", + "unit": "U/ min", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#1f77b4", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + 100.0, + 111.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.TAB_NOINTP_DEFAULT_VALUE", + "unit": "U/ min", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#ff7f0e", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + 100.0, + 111.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.TAB_NOINTP_NO_DEFAULT_VALUE", + "unit": "U/ min", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#2ca02c", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "y_range": [ + 100.0, + 111.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "ASAM.M.SCALAR.UBYTE.TAB_VERB_DEFAULT_VALUE", + "unit": "unknown signal type", + "flags": 0, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#d62728", + "computed": false, + "ranges": [], + "precision": 3, + "fmt": "{}", + "format": "phys", + "mode": "phys", + "y_range": [ + 0.0, + 255.0 + ], + "origin_uuid": "ae683e64a806" + }, + { + "type": "channel", + "name": "FirstVirtualChannel", + "unit": "", + "flags": 32, + "enabled": true, + "individual_axis": false, + "common_axis": false, + "color": "#85cf0c", + "computed": true, + "ranges": [], + "precision": 3, + "fmt": "{:.3f}", + "format": "phys", + "mode": "phys", + "computation": { + "args": {}, + "channel_comment": "", + "channel_name": "FirstVirtualChannel", + "channel_unit": "", + "computation_mode": "sample_by_sample", + "function": "TestVirtualChannel", + "triggering": "triggering_on_channel", + "triggering_value": "MAIN_CLOCK", + "type": "python_function" + }, + "y_range": [ + -1.0, + 0.0 + ], + "origin_uuid": "ae683e64a806" + } + ], + "pattern": {}, + "splitter": [ + 394, + 284, + 0 + ], + "x_range": [ + -0.7252090113273859, + 13.152907274715773 + ], + "y_axis_width": 0.0, + "grid": [ + false, + false + ], + "cursor_precision": 6, + "font_size": 9, + "locked": false, + "common_axis_y_range": [ + 0.00392156862745098, + 1.0 + ], + "channels_header": [ + 394, + [ + 366, + 83, + 122, + 35, + 35 + ] + ], + "hide_axes": true, + "hide_selected_channel_value_panel": false, + "focused_mode": false, + "delta_mode": "delta", + "hide_bookmarks": true + }, + "geometry": [ + 0, + 0, + 688, + 646 + ], + "maximized": true, + "minimized": false, + "type": "Plot" + } + ], + "functions": { + "TestVirtualChannel": "def TestVirtualChannel(t=0):\n return 1" + } +} \ No newline at end of file diff --git a/test/asammdf/gui/widgets/test_PlotWidget_ContextMenu.py b/test/asammdf/gui/widgets/test_PlotWidget_ContextMenu.py index f44edc6ef..0503757e9 100644 --- a/test/asammdf/gui/widgets/test_PlotWidget_ContextMenu.py +++ b/test/asammdf/gui/widgets/test_PlotWidget_ContextMenu.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import json from json import JSONDecodeError +import pathlib import re import sys from test.asammdf.gui.widgets.test_BasePlotWidget import TestPlotWidget @@ -8,7 +9,7 @@ from unittest import mock from unittest.mock import ANY -from PySide6 import QtCore, QtTest, QtWidgets +from PySide6 import QtCore, QtGui, QtTest, QtWidgets class TestContextMenu(TestPlotWidget): @@ -852,6 +853,7 @@ def test_Menu_EnableDisable_Action_EnableSelected(self): self.assertEqual(QtCore.Qt.Checked, group_channel.checkState(self.Column.NAME)) + @unittest.skipIf(sys.platform != "win32", "Timers cannot be started/stopped from another thread.") def test_Menu_EnableDisable_Action_DisableSelected(self): """ Test Scope: @@ -925,3 +927,447 @@ def test_Menu_EnableDisable_Action_DisableAllButThis(self): item = self.plot.channel_selection.topLevelItem(i) if item.type() != item.Info and item != self.plot_channel_b: self.assertEqual(QtCore.Qt.Unchecked, item.checkState(self.Column.NAME)) + + def test_Menu_ShowHide_Action_HideDisabledItems(self): + """ + Test Scope: + - Ensure that item is hidden from channel selection when is disabled. + Events: + - Disable 1 channel by key Space + - Disable 1 channel by mouseClick on item CheckBox + Evaluate: + - Evaluate that items that are unchecked are not present anymore on channel selection + """ + self.context_menu(action_text="Hide disabled items") + + with self.subTest("DisableBySpace"): + # Select one channel + self.mouseClick_WidgetItem(self.plot_channel_a) + # Event + QtTest.QTest.keyClick(self.plot.channel_selection, QtCore.Qt.Key_Space) + # Evaluate + self.assertTrue(self.plot_channel_a.isHidden()) + + with self.subTest("DisableByClick"): + pos = self.plot.channel_selection.visualItemRect(self.plot_channel_b).center() + # Magic Number to detect center of checkbox + pos = QtCore.QPoint(28, pos.y()) + # Event + QtTest.QTest.mouseClick( + self.plot.channel_selection.viewport(), QtCore.Qt.LeftButton, QtCore.Qt.KeyboardModifiers(), pos + ) + # Evaluate + self.assertTrue(self.plot_channel_b.isHidden()) + + def test_Menu_ShowHide_Action_ShowDisabledItems(self): + """ + Test Scope: + - Ensure that item is showed on channel selection when is disabled. + Events: + - Disable 1 channel by key Space + - Disable 1 channel by mouseClick on item CheckBox + Evaluate: + - Evaluate that items that are unchecked are not present anymore on channel selection + """ + + with self.subTest("DisableBySpace"): + self.context_menu(action_text="Hide disabled items") + # Select one channel + self.mouseClick_WidgetItem(self.plot_channel_a) + # Event + QtTest.QTest.keyClick(self.plot.channel_selection, QtCore.Qt.Key_Space) + # Evaluate + self.assertTrue(self.plot_channel_a.isHidden()) + self.context_menu(action_text="Show disabled items") + self.assertFalse(self.plot_channel_a.isHidden()) + + with self.subTest("DisableByClick"): + self.context_menu(action_text="Hide disabled items") + pos = self.plot.channel_selection.visualItemRect(self.plot_channel_b).center() + # Magic Number to detect center of checkbox + pos = QtCore.QPoint(28, pos.y()) + # Event + QtTest.QTest.mouseClick( + self.plot.channel_selection.viewport(), QtCore.Qt.LeftButton, QtCore.Qt.KeyboardModifiers(), pos + ) + # Evaluate + self.assertTrue(self.plot_channel_b.isHidden()) + self.context_menu(action_text="Show disabled items") + self.assertFalse(self.plot_channel_b.isHidden()) + + def test_Menu_ShowHide_Action_HideMissingItems(self): + """ + Test Scope: + - Ensure that missing item is hidden from channel selection. + Events: + - Disable 1 channel by key Space + - Disable 1 channel by mouseClick on item CheckBox + Evaluate: + - Evaluate that missing items are not present anymore on channel selection + """ + dspf_filepath = pathlib.Path(self.resource, "missingItems.dspf") + self.load_display_file(display_file=dspf_filepath) + self.plot = self.widget.mdi_area.subWindowList()[0].widget() + + plot_channel = self.find_channel(channel_tree=self.plot.channel_selection, channel_name="1stMissingItem") + self.processEvents() + + self.assertFalse(plot_channel.isHidden()) + + # Events + self.context_menu(action_text="Hide missing items") + + # Evaluate + self.assertTrue(plot_channel.isHidden()) + self.processEvents(timeout=0.01) + + def test_Menu_ShowHide_Action_ShowMissingItems(self): + """ + Test Scope: + - Ensure that missing item is visible from channel selection. + Events: + - Open Context Menu + - Select action: Hide missing items + - Disable 1 channel by key Space + - Disable 1 channel by mouseClick on item CheckBox + Evaluate: + - Evaluate that missing items are present anymore on channel selection + """ + dspf_filepath = pathlib.Path(self.resource, "missingItems.dspf") + self.load_display_file(display_file=dspf_filepath) + self.plot = self.widget.mdi_area.subWindowList()[0].widget() + + self.context_menu(action_text="Hide missing items") + + plot_channel = self.find_channel(channel_tree=self.plot.channel_selection, channel_name="1stMissingItem") + self.processEvents() + + self.assertTrue(plot_channel.isHidden()) + + # Events + self.context_menu(action_text="Show missing items") + + # Evaluate + self.assertFalse(plot_channel.isHidden()) + self.processEvents(timeout=0.01) + + def test_Menu_ShowHide_Action_FilterOnlyComputedChannels(self): + """ + Test Scope: + - Ensure that all channels are hidden from channel selection except VirtualChannels. + Events: + - Open Context Menu + - Select Filter Only Computed Channels + Evaluate: + - Evaluate that channels items are not present anymore on channel selection except VirtualChannels. + """ + dspf_filepath = pathlib.Path(self.resource, "missingItems.dspf") + self.load_display_file(display_file=dspf_filepath) + self.plot = self.widget.mdi_area.subWindowList()[0].widget() + + iterator = QtWidgets.QTreeWidgetItemIterator(self.plot.channel_selection) + while iterator.value(): + item = iterator.value() + if item: + self.assertFalse(item.isHidden()) + iterator += 1 + + # Events + self.context_menu(action_text="Filter only computed channels") + + # Evaluate + iterator = QtWidgets.QTreeWidgetItemIterator(self.plot.channel_selection) + while iterator.value(): + item = iterator.value() + if item and item.text(0) == "FirstVirtualChannel": + self.assertFalse(item.isHidden()) + else: + self.assertTrue(item.isHidden()) + iterator += 1 + + def test_Menu_ShowHide_Action_UnfilterComputedChannels(self): + """ + Test Scope: + - Ensure that all channels are hidden from channel selection except VirtualChannels. + Events: + - Open Context Menu + - Select Filter Only Computed Channels + Evaluate: + - Evaluate that channels items are not present anymore on channel selection except VirtualChannels. + """ + dspf_filepath = pathlib.Path(self.resource, "missingItems.dspf") + self.load_display_file(display_file=dspf_filepath) + self.plot = self.widget.mdi_area.subWindowList()[0].widget() + + # Events + self.context_menu(action_text="Filter only computed channels") + # Evaluate + iterator = QtWidgets.QTreeWidgetItemIterator(self.plot.channel_selection) + while iterator.value(): + item = iterator.value() + if item and item.text(0) == "FirstVirtualChannel": + self.assertFalse(item.isHidden()) + else: + self.assertTrue(item.isHidden()) + iterator += 1 + + # Events + self.context_menu(action_text="Un-filter computed channels") + + # Evaluate + iterator = QtWidgets.QTreeWidgetItemIterator(self.plot.channel_selection) + while iterator.value(): + item = iterator.value() + if item: + self.assertFalse(item.isHidden()) + iterator += 1 + + def test_Action_EditYAxisScaling(self): + """ + Test Scope: + - Ensure that action forwards the request to plot. + Event: + - Select channel + - Open Context Menu + - Select 'Edit Y axis scaling' + Evaluate: + - Evaluate that event is forwarded to plot + """ + # Setup + position = self.plot.channel_selection.visualItemRect(self.plot_channel_a).center() + with mock.patch.object(self.plot, "keyPressEvent") as mo_keyPressEvent: + self.context_menu(action_text="Edit Y axis scaling [Ctrl+G]", position=position) + mo_keyPressEvent.assert_called() + event = mo_keyPressEvent.call_args.args[0] + self.assertEqual(QtCore.QEvent.KeyPress, event.type()) + self.assertEqual(QtCore.Qt.Key_G, event.key()) + self.assertEqual(QtCore.Qt.ControlModifier, event.modifiers()) + + def test_Action_AddToCommonYAxis(self): + """ + Test Scope: + - Ensure that action will mark as checked checkbox for Y Axis. + Event: + - Select one channel + - Open Context Menu + - Select 'Add to common Y axis' + - Select two channels + - Open Context Menu + - Select 'Add to common Y axis' + Evaluate: + - Evaluate that checkbox on column COMMON_AXIS is checked. + """ + with self.subTest("1Channel"): + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + + position = self.plot.channel_selection.visualItemRect(self.plot_channel_a).center() + self.context_menu(action_text="Add to common Y axis", position=position) + + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + + self.context_menu(action_text="Add to common Y axis", position=position) + + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + + with self.subTest("2Channels"): + self.plot_channel_b.setSelected(True) + self.plot_channel_c.setSelected(True) + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + + position = self.plot.channel_selection.visualItemRect(self.plot_channel_c).center() + self.context_menu(action_text="Add to common Y axis", position=position) + + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + + self.context_menu(action_text="Add to common Y axis", position=position) + + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + + def test_Action_RemoveFromCommonYAxis(self): + """ + Test Scope: + - Ensure that action will mark as unchecked checkbox for Y Axis. + Event: + - Select one channel + - Open Context Menu + - Select 'Remove from common Y axis' + - Select two channels + - Open Context Menu + - Select 'Remove from common Y axis' + Evaluate: + - Evaluate that checkbox on column COMMON_AXIS is unchecked. + """ + with self.subTest("1Channel"): + # Setup + position = self.plot.channel_selection.visualItemRect(self.plot_channel_a).center() + + # Pre-evaluation + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + + # Event + self.context_menu(action_text="Remove from common Y axis", position=position) + # Evaluate + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + + # Event + self.context_menu(action_text="Add to common Y axis", position=position) + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + self.context_menu(action_text="Remove from common Y axis", position=position) + # Evaluate + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + + # Event + self.context_menu(action_text="Remove from common Y axis", position=position) + # Evaluate + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_a.checkState(self.Column.COMMON_AXIS)) + + with self.subTest("2Channels"): + # Setup + self.plot_channel_b.setSelected(True) + self.plot_channel_c.setSelected(True) + position_c = self.plot.channel_selection.visualItemRect(self.plot_channel_c).center() + + # Pre-evaluation + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + + # Event + + self.context_menu(action_text="Remove from common Y axis", position=position_c) + # Evaluate + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + + # Event + self.context_menu(action_text="Add to common Y axis", position=position_c) + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + self.context_menu(action_text="Remove from common Y axis", position=position) + # Evaluate + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + + # Event + self.context_menu(action_text="Remove from common Y axis", position=position) + # Evaluate + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_b.checkState(self.Column.COMMON_AXIS)) + self.assertNotEqual(QtCore.Qt.Checked, self.plot_channel_c.checkState(self.Column.COMMON_AXIS)) + + def test_Action_SetColor(self): + """ + Test Scope: + - Ensure that channel color is changed. + Events: + - Open Context Menu + - Select 'Set color [C]' + - Select 1 Channel + - Open Context Menu + - Select 'Set color [C]' + - Select 2 Channels + - Open Context Menu + - Select 'Set color [C]' + Evaluate: + - Evaluate that color dialog is not open if channel is not selected. + - Evaluate that channel color is changed. + """ + action_text = "Set color [C]" + + # Event + with self.subTest("NoChannelSelected"): + with mock.patch("asammdf.gui.widgets.tree.QtWidgets.QColorDialog.getColor") as mo_getColor: + self.context_menu(action_text=action_text) + mo_getColor.assert_not_called() + + with self.subTest("1ChannelSelected"): + position = self.plot.channel_selection.visualItemRect(self.plot_channel_a).center() + with mock.patch("asammdf.gui.widgets.tree.QtWidgets.QColorDialog.getColor") as mo_getColor: + # Setup + previous_color = self.plot_channel_a.color.name() + color = QtGui.QColor("red") + color_name = color.name() + mo_getColor.return_value = color + # Event + self.context_menu(action_text=action_text, position=position) + # Evaluate + current_color = self.plot_channel_a.color.name() + mo_getColor.assert_called() + self.assertNotEqual(previous_color, current_color) + self.assertEqual(color_name, current_color) + + with self.subTest("2ChannelsSelected"): + self.mouseClick_WidgetItem(self.plot_channel_b) + self.plot_channel_b.setSelected(True) + self.plot_channel_c.setSelected(True) + position = self.plot.channel_selection.visualItemRect(self.plot_channel_c).center() + with mock.patch("asammdf.gui.widgets.tree.QtWidgets.QColorDialog.getColor") as mo_getColor: + # Setup + previous_b_color = self.plot_channel_b.color.name() + previous_c_color = self.plot_channel_c.color.name() + color = QtGui.QColor("blue") + color_name = color.name() + mo_getColor.return_value = color + # Event + self.context_menu(action_text=action_text, position=position) + # Evaluate + current_b_color = self.plot_channel_b.color.name() + current_c_color = self.plot_channel_c.color.name() + mo_getColor.assert_called() + self.assertNotEqual(previous_b_color, current_b_color) + self.assertNotEqual(previous_c_color, current_c_color) + self.assertEqual(color_name, current_b_color) + self.assertEqual(color_name, current_c_color) + + def test_Action_SetRandomColor(self): + """ + Test Scope: + - Ensure that channel color is changed. + Events: + - Open Context Menu + - Select 'Set random color' + - Select 1 Channel + - Open Context Menu + - Select 'Set random color' + - Select 2 Channels + - Open Context Menu + - Select 'Set random color' + Evaluate: + - Evaluate that color dialog is not open if channel is not selected. + - Evaluate that channel color is changed. + """ + action_text = "Set random color" + + # Event + with self.subTest("NoChannelSelected"): + with mock.patch("asammdf.gui.widgets.tree.QtWidgets.QColorDialog.getColor") as mo_getColor: + self.context_menu(action_text=action_text) + mo_getColor.assert_not_called() + + with self.subTest("1ChannelSelected"): + position = self.plot.channel_selection.visualItemRect(self.plot_channel_a).center() + # Setup + previous_color = self.plot_channel_a.color.name() + # Event + self.context_menu(action_text=action_text, position=position) + # Evaluate + current_color = self.plot_channel_a.color.name() + self.assertNotEqual(previous_color, current_color) + + with self.subTest("2ChannelsSelected"): + self.mouseClick_WidgetItem(self.plot_channel_b) + self.plot_channel_b.setSelected(True) + self.plot_channel_c.setSelected(True) + position = self.plot.channel_selection.visualItemRect(self.plot_channel_c).center() + # Setup + previous_b_color = self.plot_channel_b.color.name() + previous_c_color = self.plot_channel_c.color.name() + # Event + self.context_menu(action_text=action_text, position=position) + # Evaluate + current_b_color = self.plot_channel_b.color.name() + current_c_color = self.plot_channel_c.color.name() + self.assertNotEqual(previous_b_color, current_b_color) + self.assertNotEqual(previous_c_color, current_c_color) + self.assertNotEqual(current_b_color, current_c_color) diff --git a/test/asammdf/gui/widgets/test_PlotWidget_DragAndDrop.py b/test/asammdf/gui/widgets/test_PlotWidget_DragAndDrop.py index d7031e193..b7194c8ed 100644 --- a/test/asammdf/gui/widgets/test_PlotWidget_DragAndDrop.py +++ b/test/asammdf/gui/widgets/test_PlotWidget_DragAndDrop.py @@ -8,6 +8,7 @@ from PySide6 import QtCore, QtGui, QtTest, QtWidgets +@unittest.skipIf(sys.platform != "win32", "Timers cannot be started/stopped from another thread.") class TestDragAndDrop(TestPlotWidget): # Note: Test Plot Widget through FileWidget.