import logging import random import time from unittest import mock from chirp import chirp_common from chirp import errors from tests import base LOG = logging.getLogger(__name__) class SerialException(Exception): pass class SerialNone: def flush(self): pass def inWaiting(self): return len(self.read(256)) def read(self, size=None): return b"" def write(self, data): if not isinstance(data, bytes): raise TypeError('Radio wrote non-bytes to serial') def setBaudrate(self, rate): pass def setTimeout(self, timeout): pass def setParity(self, parity): pass def __str__(self): return self.__class__.__name__.replace("Serial", "") class SerialError(SerialNone): def read(self, size=None): raise SerialException("Foo") def write(self, data): raise SerialException("Bar") class SerialGarbage(SerialNone): def read(self, size=None): if size is None: size = random.randint(0, 128) buf = [] for i in range(0, size): buf.append(i % 256) return bytes(buf) class SerialShortGarbage(SerialNone): def read(self, size=None): if size is None: size = random.randint(0, 128) return b'\x01' * (size - 1) class TestCaseClone(base.DriverTest): def setUp(self): super().setUp() self.live = isinstance(self.radio, chirp_common.LiveRadio) self.clone = isinstance(self.radio, chirp_common.CloneModeRadio) if not self.clone and not self.live: self.skipTest('Does not support clone') real_time = time.time def fake_time(): return real_time() * 1000 self.patches = [] self.use_patch(mock.patch('time.sleep')) self.use_patch(mock.patch('time.time', side_effect=fake_time)) def _test_with_serial(self, serial): # The base case sets us up with a file, so re-init with our serial. # The radio must not read (or fail) with unexpected/error serial # behavior on init. LOG.info('Initializing radio with fake serial; Radio should not fail') orig_mmap = self.parent._mmap try: cls = self.RADIO_CLASS.detect_from_serial(serial) if cls and cls != self.RADIO_CLASS: self.fail('Radio detection did not return self') except NotImplementedError: pass except errors.RadioError: pass except SerialException: pass self.radio = self.RADIO_CLASS(serial) self.radio._mmap = orig_mmap self.radio.status_fn = lambda s: True msg = ('Clone should have failed and raised an exception ' 'that inherits from RadioError') with self.assertRaises(errors.RadioError, msg=msg): self.radio.sync_in() msg = ('Clone should have failed and raised an exception ' 'that inherits from RadioError') with self.assertRaises(errors.RadioError, msg=msg): self.radio.sync_out() def test_clone_serial_error(self): self._test_with_serial(SerialError()) def test_clone_serial_none(self): self._test_with_serial(SerialNone()) def test_clone_serial_garbage(self): self._test_with_serial(SerialGarbage()) def test_clone_serial_short_garbage(self): self._test_with_serial(SerialShortGarbage())