Coverage for hdl_registers/test/unit/test_register_list.py: 100%
216 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-29 22:03 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-29 22:03 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the hdl_registers project, a HDL register generator fast enough to be run
5# in real time.
6# https://hdl-registers.com
7# https://gitlab.com/hdl_registers/hdl_registers
8# --------------------------------------------------------------------------------------------------
10# Standard libraries
11import copy
12import unittest
13from pathlib import Path
14from unittest.mock import patch
16# Third party libraries
17import pytest
18from tsfpga.system_utils import create_file
20# First party libraries
21from hdl_registers.parser import from_toml
22from hdl_registers.register import Register
23from hdl_registers.register_list import RegisterList
26def test_from_default_registers():
27 register_a = Register(name="a", index=0, mode="r", description="AA")
28 register_b = Register(name="b", index=1, mode="w", description="BB")
29 default_registers = [register_a, register_b]
31 register_list = RegisterList.from_default_registers(
32 name="apa", source_definition_file=None, default_registers=default_registers
33 )
35 # Change some things in the register objects to show that they are copied
36 default_registers.append(Register(name="c", index=2, mode="r_w", description="CC"))
37 register_a.mode = "w"
38 register_b.name = "x"
40 assert len(register_list.register_objects) == 2
41 assert register_list.get_register("a").mode == "r"
42 assert register_list.get_register("b").name == "b"
45@patch("hdl_registers.register_list.git_commands_are_available", autospec=True)
46@patch("hdl_registers.register_list.get_git_commit", autospec=True)
47@patch("hdl_registers.register_list.svn_commands_are_available", autospec=True)
48@patch("hdl_registers.register_list.get_svn_revision_information", autospec=True)
49def test_generated_source_info(
50 get_svn_revision_information,
51 svn_commands_are_available,
52 get_git_commit,
53 git_commands_are_available,
54):
55 source_definition_file = Path("/apa/whatever/regs.toml")
56 register_list = RegisterList(name="a", source_definition_file=source_definition_file)
57 expected_first_line = "This file is automatically generated by hdl_registers."
59 # Test with git information
60 git_commands_are_available.return_value = True
61 get_git_commit.return_value = "HASH"
63 got = register_list.generated_source_info()
64 assert got[0] == expected_first_line
65 assert " from file regs.toml at commit HASH." in got[1]
67 # Test with SVN information
68 git_commands_are_available.return_value = False
69 svn_commands_are_available.return_value = True
70 get_svn_revision_information.return_value = "REVISION"
72 got = register_list.generated_source_info()
73 assert got[0] == expected_first_line
74 assert " from file regs.toml at revision REVISION." in got[1]
76 # Test with no source definition file
77 register_list = RegisterList(name="a", source_definition_file=None)
79 got = register_list.generated_source_info()
80 assert got[0] == expected_first_line
81 assert "from file" not in got[1]
82 assert " at revision REVISION." in got[1]
85def test_header_constants():
86 registers = RegisterList(name="apa", source_definition_file=None)
87 hest = registers.add_constant("hest", 123)
88 zebra = registers.add_constant("zebra", 456, "description")
90 assert len(registers.constants) == 2
92 assert registers.get_constant("hest") == hest
93 assert registers.get_constant("zebra") == zebra
95 with pytest.raises(ValueError) as exception_info:
96 assert registers.get_constant("non existing") is None
97 assert (
98 str(exception_info.value)
99 == 'Could not find constant "non existing" within register list "apa"'
100 )
102 zebra.value = -5
103 assert registers.get_constant("zebra").value == -5
106def test_invalid_register_mode_should_raise_exception():
107 registers = RegisterList(None, None)
108 registers.append_register(name="test", mode="r_w", description="")
110 with pytest.raises(ValueError) as exception_info:
111 registers.append_register(name="hest", mode="x", description="")
112 assert str(exception_info.value) == 'Invalid mode "x" for register "hest"'
114 register_array = registers.append_register_array("array", 2, "")
115 register_array.append_register(name="apa", mode="r", description="")
116 with pytest.raises(ValueError) as exception_info:
117 register_array.append_register(name="zebra", mode="y", description="")
118 assert str(exception_info.value) == 'Invalid mode "y" for register "zebra"'
121def test_registers_are_appended_properly_and_can_be_edited_in_place():
122 register_array = RegisterList(name="apa", source_definition_file=Path("."))
124 register_hest = register_array.append_register(name="hest", mode="r", description="")
125 assert register_hest.index == 0
127 register_zebra = register_array.append_register(name="zebra", mode="r", description="")
128 assert register_zebra.index == 1
130 register_hest.description = "new desc"
131 assert register_array.register_objects[0].description == "new desc"
134def test_register_arrays_are_appended_properly_and_can_be_edited_in_place():
135 register_array = RegisterList(name="apa", source_definition_file=Path("."))
137 register_array_hest = register_array.append_register_array(
138 name="hest", length=4, description=""
139 )
140 assert register_array_hest.base_index == 0
141 register_array_hest.append_register(name="foo", mode="r", description="")
142 register_array_hest.append_register(name="bar", mode="w", description="")
144 register_array_zebra = register_array.append_register_array(
145 name="zebra", length=2, description=""
146 )
147 assert register_array_zebra.base_index == 8
150def test_get_register():
151 register_list = RegisterList(name="apa", source_definition_file=None)
152 hest = register_list.append_register(name="hest", mode="r", description="")
153 zebra = register_list.append_register(name="zebra", mode="r", description="")
154 register_list.append_register_array(name="register_array", length=3, description="")
156 assert register_list.get_register("hest") is hest
157 assert register_list.get_register("zebra") is zebra
159 with pytest.raises(ValueError) as exception_info:
160 assert register_list.get_register("non existing") is None
161 assert (
162 str(exception_info.value)
163 == 'Could not find register "non existing" within register list "apa"'
164 )
166 with pytest.raises(ValueError) as exception_info:
167 assert register_list.get_register("register_array") is None
168 assert (
169 str(exception_info.value)
170 == 'Could not find register "register_array" within register list "apa"'
171 )
172 register_list.get_register_array("register_array")
175def test_get_register_array():
176 register_list = RegisterList(name="apa", source_definition_file=None)
177 hest = register_list.append_register_array(name="hest", length=3, description="")
178 zebra = register_list.append_register_array(name="zebra", length=2, description="")
179 register_list.append_register(name="register", mode="r", description="")
181 assert register_list.get_register_array("hest") is hest
182 assert register_list.get_register_array("zebra") is zebra
184 with pytest.raises(ValueError) as exception_info:
185 assert register_list.get_register_array("non existing") is None
186 assert (
187 str(exception_info.value)
188 == 'Could not find register array "non existing" within register list "apa"'
189 )
191 with pytest.raises(ValueError) as exception_info:
192 assert register_list.get_register_array("register") is None
193 assert (
194 str(exception_info.value)
195 == 'Could not find register array "register" within register list "apa"'
196 )
197 register_list.get_register("register")
200def test_get_register_index():
201 register_list = RegisterList(name=None, source_definition_file=None)
203 register_list.append_register(name="apa", mode="r", description="")
204 register_list.append_register(name="hest", mode="r", description="")
206 zebra = register_list.append_register_array(name="zebra", length=2, description="")
207 zebra.append_register(name="bar", mode="r", description="")
208 zebra.append_register(name="baz", mode="r", description="")
210 assert register_list.get_register_index(register_name="apa") == 0
211 assert register_list.get_register_index(register_name="hest") == 1
212 assert (
213 register_list.get_register_index(
214 register_name="bar", register_array_name="zebra", register_array_index=0
215 )
216 == 2
217 )
218 assert (
219 register_list.get_register_index(
220 register_name="baz", register_array_name="zebra", register_array_index=1
221 )
222 == 5
223 )
226def test_repr_basic():
227 # Check that repr is an actual representation, not just "X object at 0xABCDEF"
228 assert "apa" in repr(RegisterList(name="apa", source_definition_file=Path(".")))
230 # Different name
231 assert repr(RegisterList(name="apa", source_definition_file=Path("."))) != repr(
232 RegisterList(name="hest", source_definition_file=Path("."))
233 )
235 # Different source_definition_file
236 assert repr(RegisterList(name="apa", source_definition_file=Path("."))) != repr(
237 RegisterList(name="apa", source_definition_file=Path("./zebra"))
238 )
241def test_repr_with_constant_added():
242 register_list_a = RegisterList(name="apa", source_definition_file=Path("."))
243 register_list_b = RegisterList(name="apa", source_definition_file=Path("."))
244 assert repr(register_list_a) == repr(register_list_b)
246 register_list_a.add_constant(name="zebra", value=3)
248 assert repr(register_list_a) != repr(register_list_b)
251def test_repr_with_register_appended():
252 register_list_a = RegisterList(name="apa", source_definition_file=Path("."))
253 register_list_b = RegisterList(name="apa", source_definition_file=Path("."))
254 assert repr(register_list_a) == repr(register_list_b)
256 register_list_a.append_register(name="zebra", mode="w", description="")
258 assert repr(register_list_a) != repr(register_list_b)
261def test_repr_with_register_array_appended():
262 register_list_a = RegisterList(name="apa", source_definition_file=Path("."))
263 register_list_b = RegisterList(name="apa", source_definition_file=Path("."))
264 assert repr(register_list_a) == repr(register_list_b)
266 register_list_a.append_register_array(name="zebra", length=4, description="")
268 assert repr(register_list_a) != repr(register_list_b)
271def test_deep_copy_of_register_list_actually_copies_everything():
272 original_list = RegisterList("original", Path("/original_file.txt"))
273 original_list.add_constant("original_constant", value=2, description="original constant")
274 original_list.append_register("original_register", "w", description="original register")
275 original_array = original_list.append_register_array("original_array", length=4, description="")
276 original_array.append_register(name="original_register_in_array", mode="r", description="")
278 copied_list = copy.deepcopy(original_list)
280 assert copied_list.constants is not original_list.constants
281 assert copied_list.constants[0] is not original_list.constants[0]
283 copied_list.add_constant(name="new_constant", value=5)
284 assert len(copied_list.constants) == 2 and len(original_list.constants) == 1
286 assert copied_list.register_objects is not original_list.register_objects
287 assert copied_list.register_objects[0] is not original_list.register_objects[0]
289 # Original register in position 0, original register array in position 1, new register in 2
290 copied_list.append_register(name="new_register", mode="r", description="")
291 assert len(copied_list.register_objects) == 3 and len(original_list.register_objects) == 2
293 assert copied_list.register_objects[1] is not original_list.register_objects[1]
294 assert (
295 copied_list.register_objects[1].registers is not original_list.register_objects[1].registers
296 )
297 assert (
298 copied_list.register_objects[1].registers[0]
299 is not original_list.register_objects[1].registers[0]
300 )
301 copied_list.register_objects[1].append_register(
302 name="new_register_in_array", mode="r_w", description=""
303 )
304 assert len(copied_list.register_objects[1].registers) == 2
305 assert len(original_list.register_objects[1].registers) == 1
308# pylint: disable=too-many-public-methods
309@pytest.mark.usefixtures("fixture_tmp_path")
310class TestRegisterList(unittest.TestCase):
312 tmp_path = None
314 module_name = "sensor"
315 toml_data = """\
316################################################################################
317[register.data]
319mode = "w"
320description = "My register"
322"""
324 def setUp(self):
325 self.toml_file = self.create_toml_file_with_extras()
327 def create_toml_file_with_extras(self, toml_extras=""):
328 data = self.toml_data + toml_extras
329 return create_file(self.tmp_path / "sensor_regs.toml", data)
331 def test_create_vhdl_package_should_not_run_if_nothing_has_changed(self):
332 register_list = from_toml(self.module_name, self.toml_file)
333 register_list.add_constant(name="apa", value=3)
334 register_list.create_vhdl_package(self.tmp_path)
336 register_list = from_toml(self.module_name, self.toml_file)
337 register_list.add_constant(name="apa", value=3)
338 with patch(
339 "hdl_registers.register_list.RegisterList._create_vhdl_package", autospec=True
340 ) as mocked_create_vhdl_package:
341 register_list.create_vhdl_package(self.tmp_path)
342 mocked_create_vhdl_package.assert_not_called()
344 def test_create_vhdl_package_should_run_if_hash_or_version_can_not_be_read(self):
345 register_list = from_toml(self.module_name, self.toml_file)
346 register_list.create_vhdl_package(self.tmp_path)
348 # Overwrite the generated file, without a valid header
349 vhd_file = self.tmp_path / "sensor_regs_pkg.vhd"
350 assert vhd_file.exists()
351 create_file(vhd_file, contents="-- Mumbo jumbo\n")
353 register_list = from_toml(self.module_name, self.toml_file)
354 with patch(
355 "hdl_registers.register_list.RegisterList._create_vhdl_package", autospec=True
356 ) as mocked_create_vhdl_package:
357 register_list.create_vhdl_package(self.tmp_path)
358 mocked_create_vhdl_package.assert_called_once()
360 def test_create_vhdl_package_should_run_again_if_toml_file_has_changed(self):
361 register_list = from_toml(self.module_name, self.toml_file)
362 register_list.create_vhdl_package(self.tmp_path)
364 self.create_toml_file_with_extras(
365 """
366[constant.apa]
368value = 3
369"""
370 )
371 register_list = from_toml(self.module_name, self.toml_file)
372 with patch(
373 "hdl_registers.register_list.RegisterList._create_vhdl_package", autospec=True
374 ) as mocked_create_vhdl_package:
375 register_list.create_vhdl_package(self.tmp_path)
376 mocked_create_vhdl_package.assert_called_once()
378 def test_create_vhdl_package_should_run_again_if_list_is_modified(self):
379 register_list = from_toml(self.module_name, self.toml_file)
380 register_list.create_vhdl_package(self.tmp_path)
382 register_list = from_toml(self.module_name, self.toml_file)
383 register_list.add_constant(name="apa", value=3)
384 with patch(
385 "hdl_registers.register_list.RegisterList._create_vhdl_package", autospec=True
386 ) as mocked_create_vhdl_package:
387 register_list.create_vhdl_package(self.tmp_path)
388 mocked_create_vhdl_package.assert_called_once()
390 def test_create_vhdl_package_should_run_again_if_version_is_changed(self):
391 register_list = from_toml(self.module_name, self.toml_file)
392 register_list.create_vhdl_package(self.tmp_path)
394 with patch(
395 "hdl_registers.register_list.RegisterList._create_vhdl_package", autospec=True
396 ) as mocked_create_vhdl_package, patch(
397 "hdl_registers.register_list.__version__", autospec=True
398 ) as _:
399 register_list.create_vhdl_package(self.tmp_path)
400 mocked_create_vhdl_package.assert_called_once()