Coverage for hdl_registers/field/test/test_integer.py: 100%
136 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 20:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 20:51 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the hdl-registers project, an HDL register generator fast enough to run
5# in real time.
6# https://hdl-registers.com
7# https://github.com/hdl-registers/hdl-registers
8# --------------------------------------------------------------------------------------------------
10# Standard libraries
11from copy import copy
13# Third party libraries
14import pytest
16# First party libraries
17from hdl_registers.field.integer import Integer
19TEST_FIELD = Integer(
20 name="apa",
21 base_index=3,
22 description="hest",
23 min_value=120,
24 max_value=456,
25 default_value=127,
26)
29def test_fields():
30 assert TEST_FIELD.name == "apa"
31 assert TEST_FIELD.base_index == 3
32 assert TEST_FIELD.description == "hest"
33 assert TEST_FIELD.min_value == 120
34 assert TEST_FIELD.max_value == 456
35 assert TEST_FIELD.default_value == 127
38def test_repr_is_an_actual_representation():
39 # Check that repr is an actual representation, not just "X object at 0xABCDEF"
40 assert "apa" in repr(TEST_FIELD)
43def test_repr_is_same_after_copy():
44 field = copy(TEST_FIELD)
46 assert repr(field) == repr(TEST_FIELD)
49def test_repr_should_change_when_name_is_changed():
50 field = copy(TEST_FIELD)
51 field.name = "zebra"
53 assert repr(field) != repr(TEST_FIELD)
56def test_repr_should_change_when_default_value_is_changed():
57 field = copy(TEST_FIELD)
58 field.default_value = 133
60 assert repr(field) != repr(TEST_FIELD)
63def test_repr_when_static_members_have_different_value():
64 original_field = Integer(
65 name="apa",
66 base_index=0,
67 description="",
68 min_value=10,
69 max_value=10,
70 default_value=10,
71 )
73 # Different base_index
74 assert repr(
75 Integer(
76 name="apa",
77 base_index=25,
78 description="",
79 min_value=10,
80 max_value=10,
81 default_value=10,
82 )
83 ) != repr(original_field)
85 # Different description
86 assert repr(
87 Integer(
88 name="apa",
89 base_index=0,
90 description="blah",
91 min_value=10,
92 max_value=10,
93 default_value=10,
94 )
95 ) != repr(original_field)
97 # Different min_value
98 assert repr(
99 Integer(
100 name="apa",
101 base_index=0,
102 description="",
103 min_value=5,
104 max_value=10,
105 default_value=10,
106 )
107 ) != repr(original_field)
109 # Different max_value
110 assert repr(
111 Integer(
112 name="apa",
113 base_index=0,
114 description="",
115 min_value=10,
116 max_value=15,
117 default_value=10,
118 )
119 ) != repr(original_field)
122def test_is_signed():
123 def get_is_signed(min_value, max_value):
124 return Integer(
125 name="",
126 base_index=0,
127 description="",
128 min_value=min_value,
129 max_value=max_value,
130 default_value=min_value,
131 ).is_signed
133 assert get_is_signed(min_value=-10, max_value=10)
134 assert get_is_signed(min_value=-10, max_value=-5)
135 assert not get_is_signed(min_value=0, max_value=10)
136 assert not get_is_signed(min_value=5, max_value=10)
139def test_non_ascending_range_should_raise_exception():
140 with pytest.raises(ValueError) as exception_info:
141 Integer(
142 name="apa", base_index=0, description="", min_value=10, max_value=0, default_value=0
143 )
145 assert (
146 str(exception_info.value)
147 == 'Integer field "apa" should have ascending range. Got: [10, 0].'
148 )
151def test_non_integer_range_should_raise_exception():
152 with pytest.raises(ValueError) as exception_info:
153 Integer(
154 name="apa",
155 base_index=0,
156 description="",
157 min_value="5",
158 max_value=10,
159 default_value=11,
160 )
161 assert (
162 str(exception_info.value)
163 == 'Integer field "apa" should have integer value for "min_value". Got: "5".'
164 )
166 with pytest.raises(ValueError) as exception_info:
167 Integer(
168 name="apa",
169 base_index=0,
170 description="",
171 min_value=5,
172 max_value="X",
173 default_value=11,
174 )
175 assert (
176 str(exception_info.value)
177 == 'Integer field "apa" should have integer value for "max_value". Got: "X".'
178 )
181def test_get_value_unsigned():
182 integer = Integer(
183 name="", base_index=2, min_value=0, max_value=127, description="", default_value=0
184 )
185 assert integer.width == 7
187 register_value = int("0101010_11", base=2)
188 assert integer.get_value(register_value) == 42
190 register_value = int("1010101_00", base=2)
191 assert integer.get_value(register_value) == 85
194def test_get_value_signed():
195 integer = Integer(
196 name="", base_index=3, min_value=-128, max_value=127, description="", default_value=0
197 )
198 assert integer.width == 8
200 register_value = int("10101010_111", base=2)
201 assert integer.get_value(register_value) == -86
203 register_value = int("01010101_000", base=2)
204 assert integer.get_value(register_value) == 85
207def test_get_value_should_raise_exception_if_value_out_of_range():
208 integer = Integer(
209 name="apa", base_index=0, min_value=0, max_value=4, description="", default_value=0
210 )
211 assert integer.width == 3
213 with pytest.raises(ValueError) as exception_info:
214 integer.get_value(7)
215 assert (
216 str(exception_info.value)
217 == 'Register field value "7" not inside "apa" field\'s legal range: (0, 4).'
218 )
221def test_set_value_unsigned():
222 integer = Integer(
223 name="", base_index=5, min_value=0, max_value=7, description="", default_value=0
224 )
225 assert integer.width == 3
227 assert integer.set_value(5) == int("101_00000", base=2)
228 assert integer.set_value(2) == int("010_00000", base=2)
231def test_set_value_signed():
232 integer = Integer(
233 name="", base_index=5, min_value=-8, max_value=7, description="", default_value=0
234 )
235 assert integer.width == 4
237 assert integer.set_value(5) == int("0101_00000", base=2)
238 assert integer.set_value(-6) == int("1010_00000", base=2)
241def test_set_value_should_raise_exception_if_value_out_of_range():
242 integer = Integer(
243 name="apa", base_index=5, min_value=-1, max_value=7, description="", default_value=0
244 )
246 with pytest.raises(ValueError) as exception_info:
247 integer.set_value(-8)
248 assert str(exception_info.value) == 'Value "-8" not inside "apa" field\'s legal range: (-1, 7).'
251def test_default_value_uint():
252 def _get_default_value_uint(min_value, max_value, default_value):
253 return Integer(
254 name="",
255 base_index=0,
256 description="",
257 min_value=min_value,
258 max_value=max_value,
259 default_value=default_value,
260 ).default_value_uint
262 assert _get_default_value_uint(min_value=5, max_value=10, default_value=7) == 7
263 assert _get_default_value_uint(min_value=-10, max_value=10, default_value=3) == 3
265 # Negative values, converted to positive and sign extended to the width of the field.
266 assert _get_default_value_uint(min_value=-10, max_value=10, default_value=-9) == 0b10111
267 assert _get_default_value_uint(min_value=-10, max_value=10, default_value=-6) == 0b11010
270def test_default_value_of_bad_type_should_raise_exception():
271 with pytest.raises(ValueError) as exception_info:
272 Integer(
273 name="apa",
274 base_index=0,
275 description="",
276 min_value=5,
277 max_value=10,
278 default_value="7",
279 )
280 assert (
281 str(exception_info.value)
282 == 'Integer field "apa" should have integer value for "default_value". Got: "7".'
283 )
285 field = Integer(
286 name="apa",
287 base_index=0,
288 description="",
289 min_value=5,
290 max_value=10,
291 default_value=5,
292 )
294 with pytest.raises(ValueError) as exception_info:
295 field.default_value = "8"
296 assert (
297 str(exception_info.value)
298 == 'Integer field "apa" should have integer value for "default_value". Got: "8".'
299 )
302def test_default_value_out_of_range_should_raise_exception():
303 with pytest.raises(ValueError) as exception_info:
304 Integer(
305 name="apa",
306 base_index=0,
307 description="",
308 min_value=5,
309 max_value=10,
310 default_value=11,
311 )
312 assert (
313 str(exception_info.value)
314 == 'Integer field "apa" should have "default_value" within range [5, 10]. Got: "11".'
315 )
317 field = Integer(
318 name="apa",
319 base_index=0,
320 description="",
321 min_value=5,
322 max_value=10,
323 default_value=5,
324 )
326 with pytest.raises(ValueError) as exception_info:
327 field.default_value = 120
328 assert (
329 str(exception_info.value)
330 == 'Integer field "apa" should have "default_value" within range [5, 10]. Got: "120".'
331 )
334def _get_field_width(min_value, max_value):
335 return Integer(
336 name="",
337 base_index=0,
338 description="",
339 min_value=min_value,
340 max_value=max_value,
341 default_value=min_value,
342 ).width
345def test_unsigned_width():
346 assert _get_field_width(min_value=0, max_value=127) == 7
347 assert _get_field_width(min_value=0, max_value=128) == 8
348 assert _get_field_width(min_value=0, max_value=255) == 8
349 assert _get_field_width(min_value=0, max_value=256) == 9
351 # The lower bound of the range does not affect the width
352 # (but it will add checkers in our generated code).
353 assert _get_field_width(min_value=255, max_value=255) == 8
356def test_signed_width():
357 # Positive range has greater demand than negative
358 assert _get_field_width(min_value=-4, max_value=16) == 5 + 1
359 assert _get_field_width(min_value=-4, max_value=4) == 3 + 1
361 # Negative range has greater demand than positive
362 assert _get_field_width(min_value=-7, max_value=2) == 4
363 assert _get_field_width(min_value=-8, max_value=2) == 4
364 assert _get_field_width(min_value=-9, max_value=2) == 5
366 assert _get_field_width(min_value=-15, max_value=7) == 5
367 assert _get_field_width(min_value=-16, max_value=7) == 5
368 assert _get_field_width(min_value=-17, max_value=7) == 6
370 # The upper bound of the range here does not affect the width
371 # (but it will add checkers in our generated code).
372 assert _get_field_width(min_value=-8, max_value=-3) == 4
373 assert _get_field_width(min_value=-16, max_value=-4) == 5
376def test_width_out_of_range_should_raise_exception():
377 def _test_width_out_of_range(min_value, max_value):
378 with pytest.raises(ValueError) as exception_info:
379 _get_field_width(min_value=min_value, max_value=max_value)
380 assert (
381 str(exception_info.value)
382 == f"Supplied integer range [{min_value}, {max_value}] does not fit in a register."
383 )
385 # Unsigned. Just within range, should not raise exception.
386 _get_field_width(min_value=128, max_value=2**32 - 1)
387 # Just outside of range.
388 _test_width_out_of_range(min_value=128, max_value=2**32)
390 # Signed, limited by negative range. Just within range, should not raise exception.
391 _get_field_width(min_value=-(2**31), max_value=128)
392 # Just outside of range.
393 _test_width_out_of_range(min_value=-(2**31) - 1, max_value=128)
395 # Signed, limited by positive range. Just within range, should not raise exception.
396 _get_field_width(min_value=-128, max_value=2**31 - 1)
397 # Just outside of range.
398 _test_width_out_of_range(min_value=-128, max_value=2**31)