mirror of
https://github.com/kk7ds/chirp
synced 2026-08-13 17:51:36 -04:00
This has been a warning for a while, so most of the popular drivers are fixed by now. This fixes the two remaining (obvious) ones and adds a test to prevent more from being added. Note that there may be some that still only modify the memory in edge cases that this test doesn't cover.
235 lines
8.6 KiB
Python
235 lines
8.6 KiB
Python
import pytest
|
|
from unittest import mock
|
|
|
|
from chirp import bitwise
|
|
from chirp import chirp_common
|
|
from chirp import directory
|
|
from chirp import errors
|
|
from tests import base
|
|
|
|
|
|
class TestCaseEdges(base.DriverTest):
|
|
def test_inherits_from_registered(self):
|
|
if self.rf.has_sub_devices:
|
|
devs = self.radio.get_sub_devices()
|
|
else:
|
|
devs = [self.radio]
|
|
for dev in devs:
|
|
directory.registered_class(dev.__class__)
|
|
|
|
def test_longname(self):
|
|
m = self.get_mem()
|
|
m.name = ("X" * 256) # Should be longer than any radio can handle
|
|
m.name = self.radio.filter_name(m.name)
|
|
|
|
self.radio.set_memory(m)
|
|
n = self.radio.get_memory(m.number)
|
|
|
|
self.assertEqualMem(m, n)
|
|
|
|
def test_badname(self):
|
|
m = self.get_mem()
|
|
|
|
ascii = "".join([chr(x) for x in range(ord(" "), ord("~")+1)])
|
|
for i in range(0, len(ascii), 4):
|
|
m.name = self.radio.filter_name(ascii[i:i+4])
|
|
self.radio.set_memory(m)
|
|
n = self.radio.get_memory(m.number)
|
|
self.assertEqualMem(m, n)
|
|
|
|
def test_set_does_not_modify_input(self):
|
|
m = self.get_mem()
|
|
self.radio.set_memory(chirp_common.FrozenMemory(m))
|
|
|
|
def test_bandedges(self):
|
|
m = self.get_mem()
|
|
min_step = min(self.rf.has_tuning_step and
|
|
self.rf.valid_tuning_steps or [10])
|
|
|
|
for low, high in self.rf.valid_bands:
|
|
for freq in (low, high - int(min_step * 1000)):
|
|
try:
|
|
m.freq = freq
|
|
except chirp_common.ImmutableValueError:
|
|
self.skipTest('Test memory has immutable freq')
|
|
if self.radio.validate_memory(m):
|
|
# Radio doesn't like it, so skip
|
|
continue
|
|
|
|
self.radio.set_memory(m)
|
|
n = self.radio.get_memory(m.number)
|
|
self.assertEqualMem(m, n)
|
|
|
|
def test_oddsteps(self):
|
|
odd_steps = {
|
|
145000000: [145856250, 145862500],
|
|
445000000: [445856250, 445862500],
|
|
862000000: [862731250, 862737500],
|
|
}
|
|
|
|
m = self.get_mem()
|
|
|
|
for low, high in self.rf.valid_bands:
|
|
for band, totest in list(odd_steps.items()):
|
|
if band < low or band > high:
|
|
continue
|
|
for testfreq in totest:
|
|
step = chirp_common.required_step(testfreq)
|
|
if step not in self.rf.valid_tuning_steps:
|
|
continue
|
|
|
|
try:
|
|
m.freq = testfreq
|
|
except chirp_common.ImmutableValueError:
|
|
self.skipTest('Test channel has immutable freq')
|
|
m.tuning_step = step
|
|
self.radio.set_memory(m)
|
|
n = self.radio.get_memory(m.number)
|
|
# Some radios have per-band required modes, which we
|
|
# don't care about testing here
|
|
self.assertEqualMem(m, n, ignore=['tuning_step',
|
|
'mode'])
|
|
|
|
def test_empty_to_not(self):
|
|
firstband = self.rf.valid_bands[0]
|
|
testfreq = firstband[0]
|
|
for loc in range(*self.rf.memory_bounds):
|
|
m = self.radio.get_memory(loc)
|
|
if m.empty:
|
|
m.empty = False
|
|
m.freq = testfreq
|
|
self.radio.set_memory(m)
|
|
m = self.radio.get_memory(loc)
|
|
self.assertEqual(testfreq, m.freq,
|
|
'Radio returned an unexpected frequency when'
|
|
'setting previously-empty location %i' % loc)
|
|
break
|
|
|
|
def test_delete_memory(self):
|
|
for loc in range(*self.rf.memory_bounds):
|
|
m = self.radio.get_memory(loc)
|
|
if 'empty' in m.immutable:
|
|
# This memory is not deletable
|
|
continue
|
|
if not m.empty:
|
|
m.empty = True
|
|
self.radio.set_memory(m)
|
|
m = self.radio.get_memory(loc)
|
|
self.assertTrue(m.empty,
|
|
'Radio returned non-empty memory when asked '
|
|
'to delete location %i' % loc)
|
|
break
|
|
|
|
def test_redelete_memory(self):
|
|
m = self.get_mem()
|
|
if 'empty' in m.immutable:
|
|
self.skipTest('Test memory is not deletable')
|
|
|
|
# Delete this memory
|
|
m.empty = True
|
|
self.radio.set_memory(m)
|
|
|
|
# Try to delete it again
|
|
self.radio.set_memory(m)
|
|
|
|
# Make sure it appears deleted
|
|
m2 = self.radio.get_memory(m.number)
|
|
self.assertTrue(m2.empty)
|
|
|
|
def test_get_set_specials(self):
|
|
if not self.rf.valid_special_chans:
|
|
self.skipTest('Radio has no specials')
|
|
lo, hi = self.rf.memory_bounds
|
|
for name in self.rf.valid_special_chans:
|
|
m1 = self.radio.get_memory(name)
|
|
# Flip to non-empty, but only touch it if it's false because some
|
|
# radios have empty in the immutable set.
|
|
if m1.empty:
|
|
m1.empty = False
|
|
|
|
self.assertIsInstance(m1.number, int,
|
|
('Special memory %s number %r is not an '
|
|
'integer') % (name, m1.number))
|
|
|
|
try:
|
|
del m1.extra
|
|
except AttributeError:
|
|
pass
|
|
if m1.freq > 130000000 and m1.freq < 500000000:
|
|
m1.freq += 5000
|
|
elif m1.freq == 0:
|
|
# If the memory was empty before, we likely need to pick
|
|
# a valid frequency. Use the bottom of the first supported
|
|
# band.
|
|
m1.freq = self.rf.valid_bands[0][0]
|
|
try:
|
|
self.radio.set_memory(m1)
|
|
except errors.RadioError:
|
|
# If the radio raises RadioError, assume we're editing a
|
|
# special channel that is not editable
|
|
continue
|
|
m2 = self.radio.get_memory(name)
|
|
self.assertEqualMem(m1, m2, ignore=['name'])
|
|
|
|
self.assertFalse(
|
|
lo < m1.number < hi,
|
|
'Special memory %s maps into memory bounds at %i' % (
|
|
name, m1.number))
|
|
|
|
def test_check_regular_not_special(self):
|
|
lo, hi = self.rf.memory_bounds
|
|
for i in range(lo, hi + 1):
|
|
m = self.radio.get_memory(i)
|
|
self.assertEqual('', m.extd_number,
|
|
'Non-special memory %i should not have '
|
|
'extd_number set to %r' % (i, m.extd_number))
|
|
self.assertIsInstance(m.number, int,
|
|
'Memory number %r is not an integer' %
|
|
m.number)
|
|
|
|
def test_get_memory_name_trailing_whitespace(self):
|
|
if self.radio.MODEL == 'KG-UV8E':
|
|
self.skipTest('The UV8E driver is so broken it does not even '
|
|
'parse its own test image cleanly')
|
|
for i in range(*self.rf.memory_bounds):
|
|
m = self.radio.get_memory(i)
|
|
self.assertEqual(m.name.rstrip(), m.name,
|
|
'Radio returned a memory with trailing '
|
|
'whitespace in the name')
|
|
|
|
def test_memory_name_stripped(self):
|
|
if ' ' not in self.rf.valid_characters:
|
|
self.skipTest('Radio does not support space characters')
|
|
m1 = self.get_mem()
|
|
m1.name = 'FOO '
|
|
self.radio.set_memory(m1)
|
|
m2 = self.radio.get_memory(m1.number)
|
|
self.assertEqual(m2.name.rstrip(), m2.name,
|
|
'Radio set and returned a memory with trailing '
|
|
'whitespace in the name')
|
|
|
|
|
|
class TestBitwiseStrict(base.DriverTest):
|
|
def setUp(self):
|
|
pass
|
|
|
|
def _raise(self, message):
|
|
raise SyntaxError(message)
|
|
|
|
@pytest.mark.xfail(strict=False)
|
|
@mock.patch.object(bitwise.Processor, 'assert_negative_seek',
|
|
side_effect=_raise)
|
|
def test_bitwise_negative_seek(self, mock_assert):
|
|
super().setUp()
|
|
|
|
@pytest.mark.xfail(strict=False)
|
|
@mock.patch.object(bitwise.Processor, 'assert_unnecessary_seek',
|
|
side_effect=_raise)
|
|
def test_bitwise_unnecessary_seek(self, mock_assert):
|
|
super().setUp()
|
|
|
|
@mock.patch.object(bitwise.LOG, 'error')
|
|
def test_bitwise_errors(self, mock_log):
|
|
super().setUp()
|
|
self.assertFalse(mock_log.called,
|
|
[x[0][0] for x in mock_log.call_args_list])
|