Files
urh/tests/test_simulator_tab_gui.py
Johannes Pohl 353868768d UI Upgrade of message type configuration (#532)
* first step of message type ui upgrade

* remove preselected index from ProtocolLabelDialog constructor

* remove selection changed for label

* move edit message type button to table

* remove delete button, functionality is now in table

* improve message type context menu

* add color selection to protocol label table

* allowing hiding of message types

* sync selection between message type table and message table

* make label visibility configurable in table

* enable deletion of labels in table

* update unittests

* fix selection bug

* update coveragerc

* support copy of labels to other message type

* avoid creating new object when reading message types from project

* fix test

* update changelog

* Make configuration button transparent

* selected label bold

* resize headers

* add show/hide all action

* same behaviour for label edits in tables

* adapt unittest

* cleanup on_table_selection_timer_timeout + update selection ui

* make current label and message type bold + add message type icon

* adapt unittest

* draw number of configured rules

* increase timeout for ci

* show num active rules only

* minor fixes

* increase timeout for ci

* sync show state

* disable grid

* close all -> close all files

* add close project action

* fix close project action

* clear message types on new project

* update changelog and project dialog buttons

* adapt unittests

* adapt unittests

* remove live update of qapp style to prevent segfault

* improve icon
2018-09-27 18:06:22 +02:00

404 lines
18 KiB
Python

import os
import socket
import tempfile
import time
from array import array
import numpy as np
from PyQt5.QtCore import Qt, QTimer, QPoint
from PyQt5.QtGui import QContextMenuEvent
from PyQt5.QtTest import QTest
from PyQt5.QtWidgets import QApplication, QMenu, QCompleter
from tests.QtTestCase import QtTestCase
from urh import constants
from urh.controller.MainController import MainController
from urh.controller.SimulatorTabController import SimulatorTabController
from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin
from urh.signalprocessing.Modulator import Modulator
from urh.signalprocessing.Participant import Participant
from urh.simulator.MessageItem import MessageItem
from urh.simulator.RuleItem import RuleItem
from urh.simulator.SimulatorMessage import SimulatorMessage
from urh.simulator.SimulatorRule import ConditionType
from urh.ui.ExpressionLineEdit import ExpressionLineEdit
from urh.ui.RuleExpressionValidator import RuleExpressionValidator
class TestSimulatorTabGUI(QtTestCase):
def setUp(self):
super().setUp()
self.carl = Participant("Carl", "C")
self.dennis = Participant("Dennis", "D")
self.participants = [self.carl, self.dennis]
self.project_folder = os.path.join(tempfile.gettempdir(), "simulator_project")
self.menus_to_ignore = []
def test_save_and_load(self):
assert isinstance(self.form, MainController)
stc = self.form.simulator_tab_controller # type: SimulatorTabController
self.__setup_project()
self.assertEqual(len(stc.simulator_config.get_all_items()), 0)
self.add_all_signals_to_simulator()
self.assertGreater(len(stc.simulator_config.get_all_items()), 0)
self.assertEqual(stc.simulator_message_table_model.rowCount(), 3)
rule = stc.simulator_scene.add_rule(ref_item=None, position=0)
stc.simulator_scene.add_rule_condition(rule, ConditionType.ELSE_IF)
stc.simulator_scene.add_goto_action(None, 0)
stc.simulator_scene.add_trigger_command_action(None, 0)
messages = stc.simulator_config.get_all_messages()
self.assertEqual(len(messages), 3)
for i, msg in enumerate(messages):
self.assertEqual(msg.source, self.carl, msg=str(i))
# select items
self.assertEqual(stc.simulator_message_field_model.rowCount(), 0)
stc.simulator_scene.select_all_items()
self.assertEqual(stc.simulator_message_field_model.rowCount(), 1)
self.form.close_project()
self.assertEqual(len(stc.simulator_config.get_all_items()), 0)
stc.simulator_scene.select_all_items()
self.assertEqual(stc.simulator_message_field_model.rowCount(), 0)
self.form.project_manager.set_project_folder(self.project_folder)
self.assertEqual(stc.simulator_message_table_model.rowCount(), 3)
self.assertGreater(len(stc.simulator_config.get_all_items()), 0)
stc.simulator_scene.select_all_items()
self.assertEqual(stc.simulator_message_field_model.rowCount(), 1)
def test_save_and_load_standalone(self):
assert isinstance(self.form, MainController)
self.__setup_project()
stc = self.form.simulator_tab_controller
self.assertEqual(len(stc.simulator_config.get_all_items()), 0)
self.add_all_signals_to_simulator()
self.assertGreater(len(stc.simulator_config.get_all_items()), 0)
self.assertEqual(stc.simulator_message_table_model.rowCount(), 3)
self.assertEqual(stc.participant_table_model.rowCount(), 2)
filename = os.path.join(tempfile.gettempdir(), "test.sim.xml")
if os.path.isfile(filename):
os.remove(filename)
self.form.simulator_tab_controller.save_simulator_file(filename)
self.form.close_all_files()
self.form.project_manager.participants.clear()
self.form.project_manager.project_updated.emit()
self.assertEqual(len(stc.simulator_config.get_all_items()), 0)
self.assertEqual(stc.simulator_message_table_model.rowCount(), 0)
self.assertEqual(stc.participant_table_model.rowCount(), 0)
self.form.add_files([filename])
self.assertGreater(len(stc.simulator_config.get_all_items()), 0)
self.assertEqual(stc.simulator_message_table_model.rowCount(), 3)
self.assertEqual(stc.participant_table_model.rowCount(), 2)
def test_edit_simulator_label_table(self):
self.__setup_project()
self.add_all_signals_to_simulator()
stc = self.form.simulator_tab_controller # type: SimulatorTabController
stc.simulator_scene.select_all_items()
model = stc.simulator_message_field_model
self.assertEqual(model.rowCount(), 1)
self.assertEqual(model.data(model.index(0, 3)), "1" * 8)
# constant value
model.setData(model.index(0, 2), 0, role=Qt.EditRole)
model.setData(model.index(0, 1), 0, role=Qt.EditRole)
model.setData(model.index(0, 3), "11110000", role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "11110000")
model.setData(model.index(0, 1), 1, role=Qt.EditRole)
model.setData(model.index(0, 3), "ab", role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "ab")
model.setData(model.index(0, 1), 2, role=Qt.EditRole)
model.setData(model.index(0, 3), "=", role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "=")
model.setData(model.index(0, 1), 3, role=Qt.EditRole)
model.setData(model.index(0, 3), "240", role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "240")
model.setData(model.index(0, 1), 4, role=Qt.EditRole)
model.setData(model.index(0, 3), "55", role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "55")
# get live during simulation
model.setData(model.index(0, 2), 1, role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "-")
stc.ui.tblViewFieldValues.openPersistentEditor(model.index(0, 3))
# formula
model.setData(model.index(0, 2), 2, role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "")
stc.ui.tblViewFieldValues.openPersistentEditor(model.index(0, 3))
model.setData(model.index(0, 3), "4+5", role=Qt.EditRole)
self.assertNotEqual(model.data(model.index(0, 3), role=Qt.BackgroundColorRole), constants.ERROR_BG_COLOR)
model.setData(model.index(0, 3), "item1.preamble + 42", role=Qt.EditRole)
self.assertNotEqual(model.data(model.index(0, 3), role=Qt.BackgroundColorRole), constants.ERROR_BG_COLOR)
model.setData(model.index(0, 3), "item1.preamble + 42/", role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3), role=Qt.BackgroundColorRole), constants.ERROR_BG_COLOR)
# external program
model.setData(model.index(0, 2), 3, role=Qt.EditRole)
stc.ui.tblViewFieldValues.openPersistentEditor(model.index(0, 3))
self.assertEqual(model.data(model.index(0, 3)), "")
# random value
model.setData(model.index(0, 2), 4, role=Qt.EditRole)
stc.ui.tblViewFieldValues.openPersistentEditor(model.index(0, 3))
self.assertTrue(model.data(model.index(0, 3)).startswith("Range (Decimal):"))
model.setData(model.index(0, 3), (42, 1337), role=Qt.EditRole)
self.assertEqual(model.data(model.index(0, 3)), "Range (Decimal): 42 - 1337")
def test_insert_column(self):
self.__setup_project()
self.add_all_signals_to_simulator()
stc = self.form.simulator_tab_controller # type: SimulatorTabController
stc.ui.cbViewType.setCurrentText("Hex")
lens = [len(msg) for msg in stc.simulator_message_table_model.protocol.messages]
stc.ui.tblViewMessage.selectAll()
stc.ui.tblViewMessage._insert_column(2)
for i, l in enumerate(lens):
self.assertEqual(lens[i]+4, len(stc.simulator_message_table_model.protocol.messages[i]))
stc.ui.cbViewType.setCurrentText("Bit")
stc.ui.tblViewMessage.selectAll()
stc.ui.tblViewMessage._insert_column(6)
for i, l in enumerate(lens):
self.assertEqual(lens[i]+5, len(stc.simulator_message_table_model.protocol.messages[i]))
def test_simulator_graphics_view(self):
self.__setup_project()
self.add_all_signals_to_simulator()
stc = self.form.simulator_tab_controller # type: SimulatorTabController
self.assertGreater(len(stc.simulator_config.get_all_items()), 0)
self.assertEqual(len(stc.simulator_scene.selectedItems()), 0)
# select first message
messages = stc.simulator_scene.get_all_message_items()
pos = stc.ui.gvSimulator.mapFromScene(messages[0].scenePos())
QTest.mouseClick(stc.ui.gvSimulator.viewport(), Qt.LeftButton, Qt.NoModifier, pos)
self.assertEqual(len(stc.simulator_scene.selectedItems()), 1)
self.assertIsInstance(stc.simulator_scene.selectedItems()[0], MessageItem)
rules = [item for item in stc.simulator_scene.items() if isinstance(item, RuleItem)]
self.assertEqual(len(rules), 0)
self.menus_to_ignore = [w for w in QApplication.topLevelWidgets() if isinstance(w, QMenu)]
timer = QTimer(self.form)
timer.setInterval(1)
timer.setSingleShot(True)
timer.timeout.connect(self.__on_context_menu_simulator_graphics_view_timer_timeout)
timer.start()
stc.ui.gvSimulator.contextMenuEvent(QContextMenuEvent(QContextMenuEvent.Mouse, pos))
rules = [item for item in stc.simulator_scene.items() if isinstance(item, RuleItem)]
self.assertEqual(len(rules), 1)
def test_simulator_message_table_context_menu(self):
self.__setup_project()
self.add_all_signals_to_simulator()
stc = self.form.simulator_tab_controller # type: SimulatorTabController
stc.ui.tabWidget.setCurrentIndex(1)
stc.simulator_scene.get_all_message_items()[0].setSelected(True)
self.assertEqual(stc.simulator_message_field_model.rowCount(), 1)
stc.ui.tblViewMessage.selectColumn(2)
x, y = stc.ui.tblViewMessage.columnViewportPosition(2), stc.ui.tblViewMessage.rowViewportPosition(0)
pos = QPoint(x, y)
stc.ui.tblViewMessage.context_menu_pos = pos
menu = stc.ui.tblViewMessage.create_context_menu()
names = [action.text() for action in menu.actions()]
self.assertIn("Enforce encoding", names)
add_label_action = next(action for action in menu.actions() if action.text() == "Create label...")
add_label_action.trigger()
menu.close()
stc.ui.tblViewMessage.selectRow(0)
self.assertEqual(stc.simulator_message_field_model.rowCount(), 2)
def test_expression_line_edit(self):
e = ExpressionLineEdit()
e.setCompleter(QCompleter(self.form.simulator_tab_controller.completer_model, e))
e.setValidator(RuleExpressionValidator(self.form.simulator_tab_controller.sim_expression_parser))
self.assertEqual(e.text(), "")
QTest.keyClick(e, Qt.Key_R, Qt.NoModifier)
self.assertEqual(e.text(), "r")
def test_participant_table(self):
stc = self.form.simulator_tab_controller # type: SimulatorTabController
stc.ui.tabWidget.setCurrentIndex(2)
self.assertEqual(stc.participant_table_model.rowCount(), 0)
for i in range(3):
stc.ui.btnAddParticipant.click()
QApplication.processEvents()
self.assertEqual(stc.participant_table_model.rowCount(), 3)
participants = stc.project_manager.participants
self.assertEqual(participants[0].name, "Alice")
self.assertEqual(participants[1].name, "Bob")
self.assertEqual(participants[2].name, "Carl")
stc.ui.tableViewParticipants.selectRow(1)
stc.ui.btnUp.click()
self.assertEqual(participants[0].name, "Bob")
self.assertEqual(participants[1].name, "Alice")
self.assertEqual(participants[2].name, "Carl")
stc.ui.btnDown.click()
self.assertEqual(participants[0].name, "Alice")
self.assertEqual(participants[1].name, "Bob")
self.assertEqual(participants[2].name, "Carl")
stc.ui.btnDown.click()
self.assertEqual(participants[0].name, "Alice")
self.assertEqual(participants[1].name, "Carl")
self.assertEqual(participants[2].name, "Bob")
def test_participants_list(self):
alice = Participant("Alice", "A")
bob = Participant("Bob", "B")
self.form.project_manager.participants.append(alice)
self.form.project_manager.participants.append(bob)
self.form.project_manager.project_updated.emit()
mt = self.form.compare_frame_controller.proto_analyzer.default_message_type
msg1 = SimulatorMessage(destination=alice, plain_bits=array("B", [1, 0, 1, 1]), pause=100, message_type=mt)
msg2 = SimulatorMessage(destination=bob, plain_bits=array("B", [1, 0, 1, 1]), pause=100, message_type=mt)
simulator_manager = self.form.simulator_tab_controller.simulator_config
simulator_manager.add_items([msg1, msg2], 0, simulator_manager.rootItem)
simulator_manager.add_label(5, 15, "test", parent_item=simulator_manager.rootItem.children[0])
stc = self.form.simulator_tab_controller # type: SimulatorTabController
model = stc.ui.listViewSimulate.model()
self.assertEqual(model.rowCount(), 2)
self.assertEqual(model.data(model.index(0, 0)), "Alice (A)")
self.assertEqual(model.data(model.index(1, 0)), "Bob (B)")
self.assertFalse(self.form.project_manager.participants[0].simulate)
self.assertEqual(model.data(model.index(0, 0), role=Qt.CheckStateRole), Qt.Unchecked)
self.assertFalse(self.form.project_manager.participants[1].simulate)
self.assertEqual(model.data(model.index(1, 0), role=Qt.CheckStateRole), Qt.Unchecked)
model.setData(model.index(0, 0), Qt.Checked, role=Qt.CheckStateRole)
self.assertTrue(self.form.project_manager.participants[0].simulate)
def test_valid_goto_targets(self):
stc = self.form.simulator_tab_controller
assert isinstance(stc, SimulatorTabController)
self.__setup_project()
self.add_all_signals_to_simulator()
self.assertEqual(len(stc.simulator_config.get_all_messages()), 3)
stc.ui.gvSimulator.on_add_goto_action_triggered()
self.assertEqual(stc.ui.detail_view_widget.currentWidget(), stc.ui.page_goto_action)
self.assertEqual(stc.ui.goto_combobox.count(), 3 + 1) # select item... also in combobox
stc.ui.gvSimulator.on_add_counter_action_triggered()
stc.ui.gvSimulator.on_add_sleep_action_triggered()
stc.ui.gvSimulator.on_add_goto_action_triggered()
self.assertEqual(stc.ui.goto_combobox.count(), 5 + 1) # select item... also in combobox
def test_open_simulator_dialog_and_send_mismatching_message(self):
stc = self.form.simulator_tab_controller
assert isinstance(stc, SimulatorTabController)
self.__setup_project()
self.add_all_signals_to_simulator()
stc.simulator_scene.select_all_items()
for msg in stc.simulator_scene.get_selected_messages():
msg.destination = self.dennis
stc.ui.gvSimulator.message_updated.emit(msg)
list_model = stc.ui.listViewSimulate.model()
self.assertEqual(list_model.rowCount(), 2)
list_model.setData(list_model.createIndex(1, 0), Qt.Checked, role=Qt.CheckStateRole)
dialog = stc.get_simulator_dialog()
network_sdr_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME
dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(network_sdr_name)
rcv_port = self.get_free_port()
dialog.simulator.sniffer.rcv_device.set_server_port(rcv_port)
dialog.ui.btnStartStop.click()
QTest.qWait(100)
modulator = dialog.project_manager.modulators[0] # type: Modulator
sender = NetworkSDRInterfacePlugin(raw_mode=True, sending=True)
sender.client_port = rcv_port
sender.send_raw_data(modulator.modulate("1" * 352), 1)
time.sleep(0.5)
sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1)
time.sleep(0.5)
sender.send_raw_data(modulator.modulate("10" * 176), 1)
time.sleep(0.5)
sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1)
time.sleep(0.5)
QTest.qWait(500)
simulator_log = dialog.ui.textEditSimulation.toPlainText()
self.assertIn("Received message 1", simulator_log)
self.assertIn("preamble: 11111111", simulator_log)
self.assertIn("Mismatch for label: preamble", simulator_log)
dialog.close()
def __on_context_menu_simulator_graphics_view_timer_timeout(self):
menu = next(w for w in QApplication.topLevelWidgets() if isinstance(w, QMenu)
and w.parent() is None and w not in self.menus_to_ignore)
names = [action.text() for action in menu.actions()]
self.assertIn("Source", names)
add_rule_action = next(action for action in menu.actions() if action.text() == "Add rule")
add_rule_action.trigger()
menu.close()
def __setup_project(self):
assert isinstance(self.form, MainController)
directory = self.project_folder
if not os.path.isdir(directory):
os.mkdir(directory)
if os.path.isfile(os.path.join(directory, "URHProject.xml")):
os.remove(os.path.join(directory, "URHProject.xml"))
self.form.project_manager.set_project_folder(directory, ask_for_new_project=False)
self.form.project_manager.participants[:] = self.participants
self.form.project_manager.project_updated.emit()
self.add_signal_to_form("esaver.coco")
self.assertEqual(self.form.signal_tab_controller.num_frames, 1)
self.assertEqual(self.form.compare_frame_controller.participant_list_model.rowCount(), 3)
for i in range(3):
self.form.compare_frame_controller.proto_analyzer.messages[i].participant = self.carl
self.form.compare_frame_controller.add_protocol_label(8, 15, 0, 0, False)
self.assertEqual(self.form.compare_frame_controller.label_value_model.rowCount(), 1)