Coverage for tsfpga/test/test_build_project_list.py: 100%
85 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-15 20:51 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-15 20:51 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the tsfpga project, a project platform for modern FPGA development.
5# https://tsfpga.com
6# https://github.com/tsfpga/tsfpga
7# --------------------------------------------------------------------------------------------------
9from unittest.mock import MagicMock
11import pytest
13from tsfpga.build_project_list import BuildProjectList, get_build_projects
14from tsfpga.module import BaseModule
15from tsfpga.system_utils import create_directory
16from tsfpga.vivado.project import BuildResult, VivadoProject
19@pytest.fixture
20def build_project_list_test():
21 class TestBuildProjectList:
22 @staticmethod
23 def _get_mocks(name, is_netlist_build=False):
24 project = MagicMock(spec=VivadoProject)
25 project.name = name
26 project.__str__.return_value = f"MockProject {name}"
27 project.is_netlist_build = is_netlist_build
29 # Note that his has 'success' set to True by default.
30 project.build.return_value = BuildResult(name=name, synthesis_run_name="")
32 module = MagicMock(spec=BaseModule)
33 module.name = name
34 module.get_build_projects.return_value = [project]
36 return module, project
38 def __init__(self):
39 self.module_one, self.project_one = self._get_mocks(name="one")
40 self.module_two, self.project_two = self._get_mocks(name="two")
42 self.module_three, self.project_three = self._get_mocks(
43 name="three", is_netlist_build=True
44 )
45 self.module_four, self.project_four = self._get_mocks(
46 name="four", is_netlist_build=True
47 )
49 self.modules = [self.module_one, self.module_two, self.module_three, self.module_four]
50 self.projects = [
51 self.project_one,
52 self.project_two,
53 self.project_three,
54 self.project_four,
55 ]
57 return TestBuildProjectList()
60def test_get_build_projects(build_project_list_test):
61 assert get_build_projects(
62 modules=build_project_list_test.modules,
63 project_filters=[],
64 include_netlist_not_full_builds=True,
65 ) == [
66 build_project_list_test.project_three,
67 build_project_list_test.project_four,
68 ]
69 assert get_build_projects(
70 modules=build_project_list_test.modules,
71 project_filters=[],
72 include_netlist_not_full_builds=False,
73 ) == [
74 build_project_list_test.project_one,
75 build_project_list_test.project_two,
76 ]
78 assert get_build_projects(
79 modules=build_project_list_test.modules,
80 project_filters=["thr*", "fou*"],
81 include_netlist_not_full_builds=True,
82 ) == [
83 build_project_list_test.project_three,
84 build_project_list_test.project_four,
85 ]
87 # Filter matches 'three' twice, but should only return once.
88 assert get_build_projects(
89 modules=build_project_list_test.modules,
90 project_filters=["three", "*r*"],
91 include_netlist_not_full_builds=True,
92 ) == [
93 build_project_list_test.project_three,
94 build_project_list_test.project_four,
95 ]
98def test_can_list_without_error(build_project_list_test):
99 list_str = str(BuildProjectList(build_project_list_test.projects))
100 assert "one" in list_str
101 assert "two" in list_str
104def test_create(build_project_list_test, tmp_path):
105 project_list = BuildProjectList(build_project_list_test.projects)
106 assert project_list.create(
107 projects_path=tmp_path / "projects_path",
108 num_parallel_builds=2,
109 ip_cache_path=tmp_path / "ip_cache_path",
110 )
112 for project in build_project_list_test.projects:
113 project.create.assert_called_once_with(
114 project_path=tmp_path / "projects_path" / project.name / "project",
115 ip_cache_path=tmp_path / "ip_cache_path",
116 )
119def test_create_unless_exists(build_project_list_test, tmp_path):
120 project_list = BuildProjectList([build_project_list_test.project_one])
121 assert project_list.create_unless_exists(
122 projects_path=tmp_path / "projects_path",
123 num_parallel_builds=2,
124 ip_cache_path=tmp_path / "ip_cache_path",
125 )
127 build_project_list_test.project_one.create.assert_called_once_with(
128 project_path=tmp_path / "projects_path" / "one" / "project",
129 ip_cache_path=tmp_path / "ip_cache_path",
130 )
132 # Create project file manually
133 create_directory(tmp_path / "projects_path" / "one" / "project")
134 (tmp_path / "projects_path" / "one" / "project" / "one.xpr").write_text("")
136 assert project_list.create_unless_exists(
137 projects_path=tmp_path / "projects_path",
138 num_parallel_builds=2,
139 ip_cache_path=tmp_path / "ip_cache_path",
140 )
142 # Still only called once after second create_unless_exists()
143 build_project_list_test.project_one.create.assert_called_once()
146def test_build(build_project_list_test, tmp_path):
147 project_list = BuildProjectList([build_project_list_test.project_one])
148 assert project_list.build(
149 projects_path=tmp_path / "projects_path",
150 num_parallel_builds=2,
151 num_threads_per_build=4,
152 other_build_argument=True,
153 )
155 build_project_list_test.project_one.build.assert_called_once_with(
156 project_path=tmp_path / "projects_path" / "one" / "project",
157 output_path=tmp_path / "projects_path" / "one",
158 num_threads=4,
159 other_build_argument=True,
160 )
163def test_build_fail_should_return_false(build_project_list_test, tmp_path):
164 project_list = BuildProjectList([build_project_list_test.project_one])
165 build_project_list_test.project_one.build.return_value = MagicMock(spec=BuildResult)
166 build_project_list_test.project_one.build.return_value.success = False
168 assert not project_list.build(
169 projects_path=tmp_path / "projects_path",
170 num_parallel_builds=2,
171 num_threads_per_build=4,
172 other_build_argument=True,
173 )
176def test_build_with_output_path(build_project_list_test, tmp_path):
177 project_list = BuildProjectList([build_project_list_test.project_one])
178 assert project_list.build(
179 projects_path=tmp_path / "projects_path",
180 num_parallel_builds=2,
181 num_threads_per_build=4,
182 output_path=tmp_path / "output_path",
183 )
185 build_project_list_test.project_one.build.assert_called_once_with(
186 project_path=tmp_path / "projects_path" / "one" / "project",
187 output_path=tmp_path / "output_path" / "one",
188 num_threads=4,
189 )
192def test_build_with_collect_artifacts(build_project_list_test, tmp_path):
193 project_list = BuildProjectList([build_project_list_test.project_one])
194 collect_artifacts = MagicMock()
195 assert project_list.build(
196 projects_path=tmp_path / "projects_path",
197 num_parallel_builds=2,
198 num_threads_per_build=4,
199 collect_artifacts=collect_artifacts,
200 )
202 collect_artifacts.assert_called_once_with(
203 project=build_project_list_test.project_one,
204 output_path=tmp_path / "projects_path" / "one",
205 )
208def test_build_with_collect_artifacts_and_output_path(build_project_list_test, tmp_path):
209 project_list = BuildProjectList([build_project_list_test.project_one])
210 collect_artifacts = MagicMock()
211 assert project_list.build(
212 projects_path=tmp_path / "projects_path",
213 num_parallel_builds=2,
214 num_threads_per_build=4,
215 output_path=tmp_path / "output_path",
216 collect_artifacts=collect_artifacts,
217 )
219 collect_artifacts.assert_called_once_with(
220 project=build_project_list_test.project_one,
221 output_path=tmp_path / "output_path" / "one",
222 )
225def test_build_with_collect_artifacts_return_false_should_fail_build(
226 build_project_list_test, tmp_path
227):
228 project_list = BuildProjectList([build_project_list_test.project_one])
229 collect_artifacts = MagicMock()
230 collect_artifacts.return_value = False
231 assert not project_list.build(
232 projects_path=tmp_path / "projects_path",
233 num_parallel_builds=2,
234 num_threads_per_build=4,
235 collect_artifacts=collect_artifacts,
236 )
239def test_open(build_project_list_test, tmp_path):
240 project_list = BuildProjectList(
241 [build_project_list_test.project_three, build_project_list_test.project_four]
242 )
243 assert project_list.open(projects_path=tmp_path / "projects_path")
245 build_project_list_test.project_three.open.assert_called_once_with(
246 project_path=tmp_path / "projects_path" / "three" / "project"
247 )
248 build_project_list_test.project_four.open.assert_called_once_with(
249 project_path=tmp_path / "projects_path" / "four" / "project"
250 )
251 build_project_list_test.project_one.open.assert_not_called()
252 build_project_list_test.project_two.open.assert_not_called()