diff options
Diffstat (limited to 'tests/unit/test_chirp_common.py')
| -rw-r--r-- | tests/unit/test_chirp_common.py | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/tests/unit/test_chirp_common.py b/tests/unit/test_chirp_common.py new file mode 100644 index 0000000..400c469 --- /dev/null +++ b/tests/unit/test_chirp_common.py @@ -0,0 +1,415 @@ +import base64 +import json +import os +import tempfile + +import mock + +from tests.unit import base +from chirp import CHIRP_VERSION +from chirp import chirp_common +from chirp import errors + + +class TestUtilityFunctions(base.BaseTest): + def test_parse_freq_whole(self): + self.assertEqual(chirp_common.parse_freq("146.520000"), 146520000) + self.assertEqual(chirp_common.parse_freq("146.5200"), 146520000) + self.assertEqual(chirp_common.parse_freq("146.52"), 146520000) + self.assertEqual(chirp_common.parse_freq("146"), 146000000) + self.assertEqual(chirp_common.parse_freq("1250"), 1250000000) + self.assertEqual(chirp_common.parse_freq("123456789"), + 123456789000000) + + def test_parse_freq_decimal(self): + self.assertEqual(chirp_common.parse_freq("1.0"), 1000000) + self.assertEqual(chirp_common.parse_freq("1.000000"), 1000000) + self.assertEqual(chirp_common.parse_freq("1.1"), 1100000) + self.assertEqual(chirp_common.parse_freq("1.100"), 1100000) + self.assertEqual(chirp_common.parse_freq("0.6"), 600000) + self.assertEqual(chirp_common.parse_freq("0.600"), 600000) + self.assertEqual(chirp_common.parse_freq("0.060"), 60000) + self.assertEqual(chirp_common.parse_freq(".6"), 600000) + + def test_parse_freq_whitespace(self): + self.assertEqual(chirp_common.parse_freq("1 "), 1000000) + self.assertEqual(chirp_common.parse_freq(" 1"), 1000000) + self.assertEqual(chirp_common.parse_freq(" 1 "), 1000000) + + self.assertEqual(chirp_common.parse_freq("1.0 "), 1000000) + self.assertEqual(chirp_common.parse_freq(" 1.0"), 1000000) + self.assertEqual(chirp_common.parse_freq(" 1.0 "), 1000000) + self.assertEqual(chirp_common.parse_freq(""), 0) + self.assertEqual(chirp_common.parse_freq(" "), 0) + + def test_parse_freq_bad(self): + self.assertRaises(ValueError, chirp_common.parse_freq, "a") + self.assertRaises(ValueError, chirp_common.parse_freq, "1.a") + self.assertRaises(ValueError, chirp_common.parse_freq, "a.b") + self.assertRaises(ValueError, chirp_common.parse_freq, + "1.0000001") + + def test_format_freq(self): + self.assertEqual(chirp_common.format_freq(146520000), "146.520000") + self.assertEqual(chirp_common.format_freq(54000000), "54.000000") + self.assertEqual(chirp_common.format_freq(1800000), "1.800000") + self.assertEqual(chirp_common.format_freq(1), "0.000001") + self.assertEqual(chirp_common.format_freq(1250000000), "1250.000000") + + @mock.patch('chirp.CHIRP_VERSION', new='daily-20151021') + def test_compare_version_to_current(self): + self.assertTrue(chirp_common.is_version_newer('daily-20180101')) + self.assertFalse(chirp_common.is_version_newer('daily-20140101')) + self.assertFalse(chirp_common.is_version_newer('0.3.0')) + self.assertFalse(chirp_common.is_version_newer('0.3.0dev')) + + @mock.patch('chirp.CHIRP_VERSION', new='0.3.0dev') + def test_compare_version_to_current_dev(self): + self.assertTrue(chirp_common.is_version_newer('daily-20180101')) + + def test_from_Hz(self): + # FIXME: These are wrong! Adding them here purely to test the + # python3 conversion, but they should be fixed. + self.assertEqual(140, chirp_common.from_GHz(14000000001)) + self.assertEqual(140, chirp_common.from_MHz(14000001)) + self.assertEqual(140, chirp_common.from_kHz(14001)) + + +class TestSplitTone(base.BaseTest): + def _test_split_tone_decode(self, tx, rx, **vals): + mem = chirp_common.Memory() + chirp_common.split_tone_decode(mem, tx, rx) + for key, value in list(vals.items()): + self.assertEqual(getattr(mem, key), value) + + def test_split_tone_decode_none(self): + self._test_split_tone_decode((None, None, None), + (None, None, None), + tmode='') + + def test_split_tone_decode_tone(self): + self._test_split_tone_decode(('Tone', 100.0, None), + ('', 0, None), + tmode='Tone', + rtone=100.0) + + def test_split_tone_decode_tsql(self): + self._test_split_tone_decode(('Tone', 100.0, None), + ('Tone', 100.0, None), + tmode='TSQL', + ctone=100.0) + + def test_split_tone_decode_dtcs(self): + self._test_split_tone_decode(('DTCS', 23, None), + ('DTCS', 23, None), + tmode='DTCS', + dtcs=23) + + def test_split_tone_decode_cross_tone_tone(self): + self._test_split_tone_decode(('Tone', 100.0, None), + ('Tone', 123.0, None), + tmode='Cross', + cross_mode='Tone->Tone', + rtone=100.0, + ctone=123.0) + + def test_split_tone_decode_cross_tone_dtcs(self): + self._test_split_tone_decode(('Tone', 100.0, None), + ('DTCS', 32, 'R'), + tmode='Cross', + cross_mode='Tone->DTCS', + rtone=100.0, + rx_dtcs=32, + dtcs_polarity='NR') + + def test_split_tone_decode_cross_dtcs_tone(self): + self._test_split_tone_decode(('DTCS', 32, 'R'), + ('Tone', 100.0, None), + tmode='Cross', + cross_mode='DTCS->Tone', + ctone=100.0, + dtcs=32, + dtcs_polarity='RN') + + def test_split_tone_decode_cross_dtcs_dtcs(self): + self._test_split_tone_decode(('DTCS', 32, 'R'), + ('DTCS', 25, 'R'), + tmode='Cross', + cross_mode='DTCS->DTCS', + dtcs=32, + rx_dtcs=25, + dtcs_polarity='RR') + + def test_split_tone_decode_cross_none_dtcs(self): + self._test_split_tone_decode((None, None, None), + ('DTCS', 25, 'R'), + tmode='Cross', + cross_mode='->DTCS', + rx_dtcs=25, + dtcs_polarity='NR') + + def test_split_tone_decode_cross_none_tone(self): + self._test_split_tone_decode((None, None, None), + ('Tone', 100.0, None), + tmode='Cross', + cross_mode='->Tone', + ctone=100.0) + + def _set_mem(self, **vals): + mem = chirp_common.Memory() + for key, value in list(vals.items()): + setattr(mem, key, value) + return chirp_common.split_tone_encode(mem) + + def split_tone_encode_test_none(self): + self.assertEqual(self._set_mem(tmode=''), + (('', None, None), + ('', None, None))) + + def split_tone_encode_test_tone(self): + self.assertEqual(self._set_mem(tmode='Tone', rtone=100.0), + (('Tone', 100.0, None), + ('', None, None))) + + def split_tone_encode_test_tsql(self): + self.assertEqual(self._set_mem(tmode='TSQL', ctone=100.0), + (('Tone', 100.0, None), + ('Tone', 100.0, None))) + + def split_tone_encode_test_dtcs(self): + self.assertEqual(self._set_mem(tmode='DTCS', dtcs=23, + dtcs_polarity='RN'), + (('DTCS', 23, 'R'), + ('DTCS', 23, 'N'))) + + def split_tone_encode_test_cross_tone_tone(self): + self.assertEqual(self._set_mem(tmode='Cross', cross_mode='Tone->Tone', + rtone=100.0, ctone=123.0), + (('Tone', 100.0, None), + ('Tone', 123.0, None))) + + def split_tone_encode_test_cross_tone_dtcs(self): + self.assertEqual(self._set_mem(tmode='Cross', cross_mode='Tone->DTCS', + rtone=100.0, rx_dtcs=25), + (('Tone', 100.0, None), + ('DTCS', 25, 'N'))) + + def split_tone_encode_test_cross_dtcs_tone(self): + self.assertEqual(self._set_mem(tmode='Cross', cross_mode='DTCS->Tone', + ctone=100.0, dtcs=25), + (('DTCS', 25, 'N'), + ('Tone', 100.0, None))) + + def split_tone_encode_test_cross_none_dtcs(self): + self.assertEqual(self._set_mem(tmode='Cross', cross_mode='->DTCS', + rx_dtcs=25), + (('', None, None), + ('DTCS', 25, 'N'))) + + def split_tone_encode_test_cross_none_tone(self): + self.assertEqual(self._set_mem(tmode='Cross', cross_mode='->Tone', + ctone=100.0), + (('', None, None), + ('Tone', 100.0, None))) + + +class TestStepFunctions(base.BaseTest): + _625 = [145856250, + 445856250, + 862731250, + 146118750, + ] + _125 = [145862500, + 445862500, + 862737500, + ] + _005 = [145005000, + 445005000, + 850005000, + ] + _025 = [145002500, + 445002500, + 850002500, + ] + + def test_is_fractional_step(self): + for freq in self._125 + self._625: + print(freq) + self.assertTrue(chirp_common.is_fractional_step(freq)) + + def test_is_6_25(self): + for freq in self._625: + self.assertTrue(chirp_common.is_6_25(freq)) + + def test_is_12_5(self): + for freq in self._125: + self.assertTrue(chirp_common.is_12_5(freq)) + + def test_is_5_0(self): + for freq in self._005: + self.assertTrue(chirp_common.is_5_0(freq)) + + def test_is_2_5(self): + for freq in self._025: + self.assertTrue(chirp_common.is_2_5(freq)) + + def test_required_step(self): + steps = {2.5: self._025, + 5.0: self._005, + 6.25: self._625, + 12.5: self._125, + } + for step, freqs in list(steps.items()): + for freq in freqs: + self.assertEqual(step, chirp_common.required_step(freq)) + + def test_required_step_fail(self): + self.assertRaises(errors.InvalidDataError, + chirp_common.required_step, + 146520500) + + def test_fix_rounded_step_250(self): + self.assertEqual(146106250, + chirp_common.fix_rounded_step(146106000)) + + def test_fix_rounded_step_500(self): + self.assertEqual(146112500, + chirp_common.fix_rounded_step(146112000)) + + def test_fix_rounded_step_750(self): + self.assertEqual(146118750, + chirp_common.fix_rounded_step(146118000)) + + +class TestImageMetadata(base.BaseTest): + def test_make_metadata(self): + class TestRadio(chirp_common.FileBackedRadio): + VENDOR = 'Dan' + MODEL = 'Foomaster 9000' + VARIANT = 'R' + + raw_metadata = TestRadio._make_metadata() + metadata = json.loads(base64.b64decode(raw_metadata).decode()) + expected = { + 'vendor': 'Dan', + 'model': 'Foomaster 9000', + 'variant': 'R', + 'rclass': 'TestRadio', + 'chirp_version': CHIRP_VERSION, + } + self.assertEqual(expected, metadata) + + def test_strip_metadata(self): + class TestRadio(chirp_common.FileBackedRadio): + VENDOR = 'Dan' + MODEL = 'Foomaster 9000' + VARIANT = 'R' + + raw_metadata = TestRadio._make_metadata() + raw_data = (b'foooooooooooooooooooooo' + TestRadio.MAGIC + + TestRadio._make_metadata()) + data, metadata = chirp_common.FileBackedRadio._strip_metadata(raw_data) + self.assertEqual(b'foooooooooooooooooooooo', data) + expected = { + 'vendor': 'Dan', + 'model': 'Foomaster 9000', + 'variant': 'R', + 'rclass': 'TestRadio', + 'chirp_version': CHIRP_VERSION, + } + self.assertEqual(expected, metadata) + + def test_load_mmap_no_metadata(self): + f = tempfile.NamedTemporaryFile() + f.write(b'thisisrawdata') + f.flush() + + with mock.patch('chirp.memmap.MemoryMap') as mock_mmap: + chirp_common.FileBackedRadio(None).load_mmap(f.name) + mock_mmap.assert_called_once_with(b'thisisrawdata') + + def test_load_mmap_bad_metadata(self): + f = tempfile.NamedTemporaryFile() + f.write(b'thisisrawdata') + f.write(chirp_common.FileBackedRadio.MAGIC + b'bad') + f.flush() + + with mock.patch('chirp.memmap.MemoryMap') as mock_mmap: + chirp_common.FileBackedRadio(None).load_mmap(f.name) + mock_mmap.assert_called_once_with(b'thisisrawdata') + + def test_save_mmap_includes_metadata(self): + # Make sure that a file saved with a .img extension includes + # the metadata blob + class TestRadio(chirp_common.FileBackedRadio): + VENDOR = 'Dan' + MODEL = 'Foomaster 9000' + VARIANT = 'R' + + with tempfile.NamedTemporaryFile(suffix='.Img') as f: + fn = f.name + r = TestRadio(None) + r._mmap = mock.Mock() + r._mmap.get_byte_compatible.return_value.get_packed.return_value = ( + b'thisisrawdata') + r.save_mmap(fn) + with open(fn, 'rb') as f: + filedata = f.read() + os.remove(fn) + data, metadata = chirp_common.FileBackedRadio._strip_metadata(filedata) + self.assertEqual(b'thisisrawdata', data) + expected = { + 'vendor': 'Dan', + 'model': 'Foomaster 9000', + 'variant': 'R', + 'rclass': 'TestRadio', + 'chirp_version': CHIRP_VERSION, + } + self.assertEqual(expected, metadata) + + def test_save_mmap_no_metadata_not_img_file(self): + # Make sure that if we save without a .img extension we do + # not include the metadata blob + class TestRadio(chirp_common.FileBackedRadio): + VENDOR = 'Dan' + MODEL = 'Foomaster 9000' + VARIANT = 'R' + + with tempfile.NamedTemporaryFile(suffix='.txt') as f: + fn = f.name + r = TestRadio(None) + r._mmap = mock.Mock() + r._mmap.get_byte_compatible.return_value.get_packed.return_value = ( + b'thisisrawdata') + r.save_mmap(fn) + with open(fn, 'rb') as f: + filedata = f.read() + os.remove(fn) + data, metadata = chirp_common.FileBackedRadio._strip_metadata(filedata) + self.assertEqual(b'thisisrawdata', data) + self.assertEqual({}, metadata) + + def test_load_mmap_saves_metadata_on_radio(self): + class TestRadio(chirp_common.FileBackedRadio): + VENDOR = 'Dan' + MODEL = 'Foomaster 9000' + VARIANT = 'R' + + with tempfile.NamedTemporaryFile(suffix='.img') as f: + fn = f.name + r = TestRadio(None) + r._mmap = mock.Mock() + r._mmap.get_byte_compatible.return_value.get_packed.return_value = ( + b'thisisrawdata') + r.save_mmap(fn) + + newr = TestRadio(None) + newr.load_mmap(fn) + expected = { + 'vendor': 'Dan', + 'model': 'Foomaster 9000', + 'variant': 'R', + 'rclass': 'TestRadio', + 'chirp_version': CHIRP_VERSION, + } + self.assertEqual(expected, newr.metadata) |
