Files
urh/tests/test_simulator_tab_gui.py
Johannes Pohl 26e5bbb492 Add a CLI (#440)
* add argument parser for CLI

* add pause to cli

* parse messages to send

* add send function

* use while loop instead of hard sleep

* use logger for error msg

* use tabulator for progress bar

* prepare rx mode

* use Thread for Protocol Sniffer instead of qt signals

* adapt tests

* fix thread can only be started once error

* enable receiving from command line

* support send from file

* save gain correctly

* enable rx into file

* remove unused signal

* enable raw rx and file mode

* add support for device identifier

* add support for default pause

* enable abort sending witt ctrl c

* support encodings

* make logging multiprocessing aware and add autobuild extensions to cli

* move place

* fix sniffer when receiving multiple messages at once

* add test for modulator cli parsing and fix some bugs

* extend modulator test and fix another bug

* add unittests and reorder urh_cli structure

* add tests

* adapt CI to CLI tests

* force osx

* fix osx

* adapt close dialog method

* remove close dialog method

* test read messages to send

* centralize read messages method

* increase timeout for ci

* support loading of project files to load cli values

* add sleep for ci

* add cli to deployment

* replace static calls with ProjectManager Class

* use time sleep instead of qwait

* disable gc collect call

* disable gc collect for python 3.4 only

* gc collect only for osx

* simplify cleanup

* simplify cleanup

* advanced cleanup only for windows

* cleanup also for osx

* gc collect for osx

* add unittests

* consider frozen app path

* init multiprocessing first

* enable logging on cli for windows

* use log file handler for log

* add missing import
2018-06-01 09:59:53 +02:00

403 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_all()
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()
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() == "Add protocol 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.1)
sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1)
time.sleep(0.1)
sender.send_raw_data(modulator.modulate("10" * 176), 1)
time.sleep(0.1)
sender.send_raw_data(np.zeros(1000, dtype=np.complex64), 1)
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.complex")
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)