File: test_brute_force.py

package info (click to toggle)
chirp 1%3A20251108-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 18,728 kB
  • sloc: python: 156,369; ansic: 296; sh: 219; xml: 24; makefile: 19
file content (225 lines) | stat: -rw-r--r-- 8,347 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import logging

import pytest

from chirp import chirp_common
from chirp import errors
from tests import base

LOG = logging.getLogger(__name__)


class TestCaseBruteForce(base.DriverTest):
    def set_and_compare(self, m, **kwargs):
        msgs = self.radio.validate_memory(m)
        if msgs:
            # If the radio correctly refuses memories it can't
            # store, don't fail
            return

        self.radio.set_memory(chirp_common.FrozenMemory(m))
        ret_m = self.radio.get_memory(m.number)

        # Damned Baofeng radios don't seem to properly store
        # shift and direction, so be gracious here
        if m.duplex == "split" and ret_m.duplex in ["-", "+"]:
            ret_m.offset = ret_m.freq + \
                (ret_m.offset * int(ret_m.duplex + "1"))
            ret_m.duplex = "split"

        self.assertEqualMem(m, ret_m, **kwargs)

    def test_tone(self):
        m = self.get_mem()
        for tone in chirp_common.TONES:
            for tmode in self.rf.valid_tmodes:
                if tmode not in chirp_common.TONE_MODES:
                    continue
                elif tmode in ["DTCS", "DTCS-R", "Cross"]:
                    continue  # We'll test DCS and Cross tones separately

                m.tmode = tmode
                if tmode == "":
                    pass
                elif tmode == "Tone":
                    m.rtone = tone
                elif tmode in ["TSQL", "TSQL-R"]:
                    if self.rf.has_ctone:
                        m.ctone = tone
                    else:
                        m.rtone = tone
                else:
                    self.fail("Unknown tone mode `%s'" % tmode)

                try:
                    self.set_and_compare(m)
                except errors.UnsupportedToneError:
                    # If a radio doesn't support a particular tone value,
                    # don't punish it
                    pass

    @base.requires_feature('has_dtcs')
    def test_dtcs(self):
        m = self.get_mem()
        m.tmode = "DTCS"
        for code in self.rf.valid_dtcs_codes:
            m.dtcs = code
            self.set_and_compare(m)

        if not self.rf.has_dtcs_polarity:
            return

        for pol in self.rf.valid_dtcs_pols:
            m.dtcs_polarity = pol
            self.set_and_compare(m)

    @base.requires_feature('has_cross')
    def test_cross(self):
        m = self.get_mem()
        m.tmode = "Cross"
        # No fair asking a radio to detect two identical tones as Cross instead
        # of TSQL
        m.rtone = 100.0
        m.ctone = 107.2
        m.dtcs = 506
        m.rx_dtcs = 516
        for cross_mode in self.rf.valid_cross_modes:
            m.cross_mode = cross_mode
            self.set_and_compare(m)

    @base.requires_feature('valid_duplexes')
    def test_duplex(self):
        m = self.get_mem()
        if 'duplex' in m.immutable:
            self.skipTest('Test memory has immutable duplex')
        for duplex in self.rf.valid_duplexes:
            assert duplex in ["", "-", "+", "split", "off"]
            if duplex == 'split':
                self.assertTrue(self.rf.can_odd_split,
                                'Radio supports split but does not set '
                                'can_odd_split=True in features')
                m.offset = self.rf.valid_bands[0][1] - 100000
            else:
                m.offset = chirp_common.to_kHz(int(m.tuning_step) * 2)
            m.duplex = duplex
            # Ignore the offset because we do some fudging on this and we
            # don't necessarily know the best step to use. What we care about
            # is duplex here.
            self.set_and_compare(m, ignore=['offset'])

        if self.rf.can_odd_split:
            self.assertIn('split', self.rf.valid_duplexes,
                          'Radio claims can_odd_split but split not in '
                          'valid_duplexes')

    @base.requires_feature('valid_skips')
    def test_skip(self):
        mem = self.get_mem()
        lo, hi = self.rf.memory_bounds
        # Walk through several memories, specifically across 8 and 16,
        # as many radio use bitfields for skip flags.
        for i in range(max(5, lo), min(25, hi)):
            # Walk through the skip flags twice each, to make sure we can
            # toggle them on..off..on
            for skip in self.rf.valid_skips * 2:
                m = mem.dupe()
                if 'empty' not in m.immutable:
                    m.empty = False
                m.number = i
                m.skip = skip
                self.set_and_compare(m)
                # Delete the memory each time because some radios are
                # dynamically allocated and will run out of space here.
                self.radio.erase_memory(m.number)

    @base.requires_feature('valid_modes')
    def test_mode(self):
        m = self.get_mem()
        if 'mode' in m.immutable:
            self.skipTest('Test memory has immutable duplex')

        def ensure_urcall(call):
            lst = self.radio.get_urcall_list()
            lst[0] = call
            self.radio.set_urcall_list(lst)

        def ensure_rptcall(call):
            lst = self.radio.get_repeater_call_list()
            lst[0] = call
            self.radio.set_repeater_call_list(lst)

        def freq_is_ok(freq):
            for lo, hi in self.rf.valid_bands:
                if freq > lo and freq < hi:
                    return True
            return False

        successes = 0
        for mode in self.rf.valid_modes:
            self.assertIn(mode, chirp_common.MODES,
                          'Radio exposes non-standard mode')
            tmp = m.dupe()
            if mode == "DV" and \
                isinstance(self.radio,
                           chirp_common.IcomDstarSupport):
                tmp = chirp_common.DVMemory()
                try:
                    ensure_urcall(tmp.dv_urcall)
                    ensure_rptcall(tmp.dv_rpt1call)
                    ensure_rptcall(tmp.dv_rpt2call)
                except IndexError:
                    if self.rf.requires_call_lists:
                        raise
                    else:
                        # This radio may not do call lists at all,
                        # so let it slide
                        pass
            if mode == "FM" and freq_is_ok(tmp.freq + 100000000):
                # Some radios don't support FM below approximately 30MHz,
                # so jump up by 100MHz, if they support that
                tmp.freq += 100000000

            tmp.mode = mode

            if self.rf.validate_memory(tmp):
                # A result (of error messages) from validate means the radio
                # thinks this is invalid, so don't fail the test
                LOG.warning('Failed to validate %s: %s' % (
                    tmp, self.rf.validate_memory(tmp)))
                continue

            # Ignore tuning_step because changing modes may cause step changes
            # in some radios
            self.set_and_compare(tmp, ignore=['tuning_step'])
            successes += 1

    def test_validate_all(self):
        lo, hi = self.rf.memory_bounds
        for i in range(lo, hi + 1):
            m1 = self.radio.get_memory(i)
            if m1.empty:
                continue
            errs, warns = chirp_common.split_validation_msgs(
                self.radio.validate_memory(m1))
            self.assertEqual([], errs,
                             ('Radio has validation errors for memory %i '
                              'stored in sample image: %s') % (i, m1))

    @base.requires_feature('has_nostep_tuning', equal=False)
    def test_validate_all_steps(self):
        lo, hi = self.rf.memory_bounds
        for i in range(lo, hi + 1):
            m1 = self.radio.get_memory(i)
            try:
                chirp_common.required_step(m1.freq, self.rf.valid_tuning_steps)
            except Exception as e:
                self.fail('Memory %i: %s' % (i, e))

    @pytest.mark.skip(reason='not ready yet')
    def test_get_set_all(self):
        lo, hi = self.rf.memory_bounds
        for i in range(lo, hi + 1):
            m1 = self.radio.get_memory(i)
            self.radio.set_memory(m1)
            m2 = self.radio.get_memory(i)
            self.assertEqualMem(m1, m2)