Coverage for tsfpga/test/unit/test_module.py: 99%
164 statements
« prev ^ index » next coverage.py v6.4, created at 2022-05-28 04:01 +0000
« prev ^ index » next coverage.py v6.4, created at 2022-05-28 04:01 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the tsfpga project.
5# https://tsfpga.com
6# https://gitlab.com/tsfpga/tsfpga
7# --------------------------------------------------------------------------------------------------
9from pathlib import Path
10from unittest import TestCase
11from unittest.mock import ANY, MagicMock, patch
13import pytest
15from tsfpga.module import BaseModule, get_modules
16from tsfpga.system_utils import create_file, create_directory
19def test_add_vunit_config_name():
20 module = BaseModule(path=Path(), library_name="")
22 test = MagicMock()
23 pre_config = MagicMock()
24 post_check = MagicMock()
26 module.add_vunit_config(test=test, pre_config=pre_config, post_check=post_check)
27 test.add_config.assert_called_once_with(
28 name="", generics={}, pre_config=pre_config, post_check=post_check
29 )
30 test.reset_mock()
32 module.add_vunit_config(test=test, name="apa")
33 test.add_config.assert_called_once_with(
34 name="apa", generics={}, pre_config=None, post_check=None
35 )
36 test.reset_mock()
38 module.add_vunit_config(test=test, generics=dict(apa="hest", foo="bar"))
39 test.add_config.assert_called_once_with(
40 name="apa_hest.foo_bar",
41 generics=dict(apa="hest", foo="bar"),
42 pre_config=None,
43 post_check=None,
44 )
45 test.reset_mock()
47 module.add_vunit_config(test=test, name="zebra", generics=dict(apa="hest", foo="bar"))
48 test.add_config.assert_called_once_with(
49 name="zebra.apa_hest.foo_bar",
50 generics=dict(apa="hest", foo="bar"),
51 pre_config=None,
52 post_check=None,
53 )
56def test_add_vunit_config_random_seed():
57 module = BaseModule(path=Path(), library_name="")
58 test = MagicMock()
60 # No seed at all
61 module.add_vunit_config(test=test)
62 assert "generics" not in test.add_config.call_args
64 module.add_vunit_config(test=test, set_random_seed=False)
65 assert "generics" not in test.add_config.call_args
67 # No seed, with generics set
68 module.add_vunit_config(test=test, generics={"apa": "whatever"})
69 assert "seed" not in test.add_config.call_args.kwargs["generics"]
71 # Static seed
72 module.add_vunit_config(test=test, set_random_seed=0)
73 assert isinstance(test.add_config.call_args.kwargs["generics"]["seed"], int)
74 assert test.add_config.call_args.kwargs["generics"]["seed"] == 0
76 module.add_vunit_config(test=test, set_random_seed=123)
77 assert isinstance(test.add_config.call_args.kwargs["generics"]["seed"], int)
78 assert test.add_config.call_args.kwargs["generics"]["seed"] == 123
80 # Use random seed
81 module.add_vunit_config(test=test, set_random_seed=True)
82 assert isinstance(test.add_config.call_args.kwargs["generics"]["seed"], int)
83 assert test.add_config.call_args.kwargs["generics"]["seed"] >= 0
85 # Setting explicit value should still work
86 module.add_vunit_config(test=test, generics={"seed": 711})
87 assert test.add_config.call_args.kwargs["generics"]["seed"] == 711
89 # If a value is already set it will be overwritten
90 module.add_vunit_config(test=test, generics={"seed": -5}, set_random_seed=True)
91 assert test.add_config.call_args.kwargs["generics"]["seed"] != -5
94def test_file_list_filtering(tmp_path):
95 module_name = "zebra"
96 path = tmp_path / module_name
98 create_directory(path / "folder_should_not_be_included")
99 create_file(path / "should_not_be_included.apa")
101 synth_files = {
102 create_file(path / "syn.v"),
103 create_file(path / "rtl" / "syn.v"),
104 create_file(path / "src" / "syn.vhd"),
105 create_file(path / "hdl" / "rtl" / "syn.vhd"),
106 create_file(path / "hdl" / "package" / "syn.vhd"),
107 }
109 test_files = {
110 create_file(path / "test" / "test.v"),
111 create_file(path / "rtl" / "tb" / "test.vhd"),
112 }
114 sim_files = {create_file(path / "sim" / "sim.vhd")}
116 my_module = BaseModule(path, "zebra")
118 files = {file.path for file in my_module.get_synthesis_files()}
119 assert files == synth_files
121 files = {file.path for file in my_module.get_simulation_files()}
122 assert files == synth_files | test_files | sim_files
124 files = {file.path for file in my_module.get_simulation_files(include_tests=False)}
125 assert files == synth_files | sim_files
127 files = {file.path for file in my_module.get_simulation_files(files_include=synth_files)}
128 assert files == synth_files
130 files = {file.path for file in my_module.get_simulation_files(files_avoid=synth_files)}
131 assert files == test_files | sim_files
134def test_get_synthesis_files_calls_get_simulation_files_with_correct_arguments():
135 module = BaseModule(path=Path(), library_name="")
136 with patch("tsfpga.module.BaseModule.get_synthesis_files") as get_synthesis_files:
137 module.get_simulation_files(files_include=True, files_avoid=False, apa=123)
138 get_synthesis_files.assert_called_once_with(files_include=True, files_avoid=False, apa=123)
141def test_scoped_constraints(tmp_path):
142 module_path = tmp_path / "apa"
143 create_file(module_path / "src" / "hest.vhd")
144 create_file(module_path / "scoped_constraints" / "hest.tcl")
146 my_module = BaseModule(module_path, "apa")
147 scoped_constraints = my_module.get_scoped_constraints()
148 assert len(scoped_constraints) == 1
149 assert scoped_constraints[0].ref == "hest"
152def test_scoped_constraint_entity_not_existing_should_raise_error(tmp_path):
153 module_path = tmp_path / "apa"
154 create_file(module_path / "scoped_constraints" / "hest.tcl")
156 module = BaseModule(module_path, "apa")
157 with pytest.raises(FileNotFoundError) as exception_info:
158 module.get_scoped_constraints()
159 assert str(exception_info.value).startswith("Could not find a matching entity file")
162def test_can_cast_to_string_without_error():
163 str(BaseModule(Path("dummy"), "dummy"))
166def test_test_case_name():
167 assert (
168 BaseModule.test_case_name(generics=dict(apa=3, hest_zebra="foo")) == "apa_3.hest_zebra_foo"
169 )
170 assert (
171 BaseModule.test_case_name(name="foo", generics=dict(apa=3, hest_zebra="bar"))
172 == "foo.apa_3.hest_zebra_bar"
173 )
176def test_getting_registers_calls_registers_hook(tmp_path):
177 with patch("tsfpga.module.from_toml", autospec=True) as from_toml, patch(
178 "tsfpga.module.BaseModule.registers_hook", autospec=True
179 ) as registers_hook:
180 create_file(tmp_path / "a" / "regs_a.toml")
181 module = BaseModule(path=tmp_path / "a", library_name="a")
182 registers = module.registers
184 # TOML file exists so register creation from TOML should run
185 from_toml.assert_called_once()
186 registers_hook.assert_called_once()
187 assert registers is not None
189 with patch("tsfpga.module.from_toml", autospec=True) as from_toml, patch(
190 "tsfpga.module.BaseModule.registers_hook", autospec=True
191 ) as registers_hook:
192 module = BaseModule(path=tmp_path / "b", library_name="b")
193 registers = module.registers
195 # TOML file does not exist, so register creation from TOML should not run
196 from_toml.assert_not_called()
197 # Register hook shall still run however
198 registers_hook.assert_called_once()
199 assert registers is None
202@pytest.mark.usefixtures("fixture_tmp_path")
203class TestGetModules(TestCase):
205 tmp_path = None
207 def setUp(self):
208 create_directory(self.tmp_path / "a")
209 create_directory(self.tmp_path / "b")
210 create_directory(self.tmp_path / "c")
212 self.modules_folders = [self.tmp_path]
214 def test_name_filtering_include(self):
215 modules = get_modules(self.modules_folders, names_include=["a", "b"])
216 assert set(module.name for module in modules) == set(["a", "b"])
218 def test_name_filtering_avoid(self):
219 modules = get_modules(self.modules_folders, names_avoid=["a", "b"])
220 assert set(module.name for module in modules) == set(["c"])
222 def test_name_filtering_include_and_avoid(self):
223 modules = get_modules(
224 self.modules_folders, names_include=["a", "c"], names_avoid=["b", "c"]
225 )
226 assert set(module.name for module in modules) == set(["a"])
228 def test_library_name_does_not_have_lib_suffix(self):
229 modules = get_modules(self.modules_folders)
230 assert set(module.library_name for module in modules) == set(["a", "b", "c"])
232 def test_library_name_has_lib_suffix(self):
233 modules = get_modules(self.modules_folders, library_name_has_lib_suffix=True)
234 assert set(module.library_name for module in modules) == set(["a_lib", "b_lib", "c_lib"])
236 def test_stray_file_can_exist_in_modules_folder_without_error(self):
237 create_file(self.tmp_path / "text_file.txt")
238 modules = get_modules(self.modules_folders)
239 assert len(modules) == 3
241 def test_local_override_of_module_type(self):
242 module_file_content = """
243from tsfpga.module import BaseModule
245class Module(BaseModule):
247 def id(self):
248 return """
250 create_file(self.tmp_path / "a" / "module_a.py", module_file_content + '"a"')
251 create_file(self.tmp_path / "b" / "module_b.py", module_file_content + '"b"')
253 modules = get_modules(self.modules_folders)
255 assert len(modules) == 3
256 for module in modules:
257 if module.name == "a":
258 assert module.id() == "a"
259 elif module.name == "b":
260 assert module.id() == "b"
261 elif module.name == "c":
262 assert isinstance(module, BaseModule)
263 else:
264 assert False
266 @patch("tsfpga.module.from_toml", autospec=True)
267 def test_register_object_creation_called_when_getting_synthesis_files(self, from_toml):
268 toml_file = create_file(self.tmp_path / "a" / "regs_a.toml")
270 module = get_modules(self.modules_folders).get("a")
271 module.get_synthesis_files()
272 module.get_synthesis_files()
274 from_toml.assert_called_once_with("a", toml_file, ANY)
276 @patch("tsfpga.module.from_toml", autospec=True)
277 def test_register_object_creation_called_when_getting_simulation_files(self, from_toml):
278 toml_file = create_file(self.tmp_path / "a" / "regs_a.toml")
280 module = get_modules(self.modules_folders).get("a")
281 module.get_simulation_files()
282 module.get_simulation_files()
284 from_toml.assert_called_once_with("a", toml_file, ANY)
286 @patch("tsfpga.module.from_toml", autospec=True)
287 def test_register_object_creation_called_once_when_getting_mixed_files(self, from_toml):
288 toml_file = create_file(self.tmp_path / "a" / "regs_a.toml")
290 module = get_modules(self.modules_folders).get("a")
291 module.get_synthesis_files()
292 module.get_simulation_files()
294 from_toml.assert_called_once_with("a", toml_file, ANY)