Coverage for tsfpga/test/test_build_project_list.py: 100%
102 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-29 20:51 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-29 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
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)
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]
51 return TestBuildProjectList()
54def test_can_list_without_error(build_project_list_test):
55 list_str = str(BuildProjectList(build_project_list_test.modules, project_filters=[]))
56 assert "one" in list_str
57 assert "two" in list_str
60def test_project_filtering(build_project_list_test):
61 project_list = BuildProjectList(build_project_list_test.modules, project_filters=[])
62 assert len(project_list.projects) == 2
63 assert build_project_list_test.project_one in project_list.projects
64 assert build_project_list_test.project_two in project_list.projects
66 project_list = BuildProjectList(
67 build_project_list_test.modules, project_filters=["apa", "*ne", "three", "four"]
68 )
69 assert len(project_list.projects) == 1
70 assert build_project_list_test.project_one in project_list.projects
72 project_list = BuildProjectList(
73 build_project_list_test.modules, project_filters=["one", "one", "on*"]
74 )
75 assert len(project_list.projects) == 1
76 assert build_project_list_test.project_one in project_list.projects
78 project_list = BuildProjectList(
79 build_project_list_test.modules, project_filters=[], include_netlist_not_top_builds=True
80 )
81 assert len(project_list.projects) == 2
82 assert build_project_list_test.project_three in project_list.projects
83 assert build_project_list_test.project_four in project_list.projects
85 project_list = BuildProjectList(
86 build_project_list_test.modules,
87 include_netlist_not_top_builds=True,
88 project_filters=["apa", "one", "two", "thr*"],
89 )
90 assert len(project_list.projects) == 1
91 assert build_project_list_test.project_three in project_list.projects
94def test_create(build_project_list_test, tmp_path):
95 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one", "two"])
96 assert project_list.create(
97 projects_path=tmp_path / "projects_path",
98 num_parallel_builds=2,
99 ip_cache_path=tmp_path / "ip_cache_path",
100 )
102 build_project_list_test.project_one.create.assert_called_once_with(
103 project_path=tmp_path / "projects_path" / "one" / "project",
104 ip_cache_path=tmp_path / "ip_cache_path",
105 )
107 build_project_list_test.project_two.create.assert_called_once_with(
108 project_path=tmp_path / "projects_path" / "two" / "project",
109 ip_cache_path=tmp_path / "ip_cache_path",
110 )
112 build_project_list_test.project_three.create.assert_not_called()
113 build_project_list_test.project_four.create.assert_not_called()
116def test_create_unless_exists(build_project_list_test, tmp_path):
117 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"])
118 assert project_list.create_unless_exists(
119 projects_path=tmp_path / "projects_path",
120 num_parallel_builds=2,
121 ip_cache_path=tmp_path / "ip_cache_path",
122 )
124 build_project_list_test.project_one.create.assert_called_once_with(
125 project_path=tmp_path / "projects_path" / "one" / "project",
126 ip_cache_path=tmp_path / "ip_cache_path",
127 )
129 # Create project file manually
130 create_directory(tmp_path / "projects_path" / "one" / "project")
131 (tmp_path / "projects_path" / "one" / "project" / "one.xpr").write_text("")
133 assert project_list.create_unless_exists(
134 projects_path=tmp_path / "projects_path",
135 num_parallel_builds=2,
136 ip_cache_path=tmp_path / "ip_cache_path",
137 )
139 # Still only called once after second create_unless_exists()
140 build_project_list_test.project_one.create.assert_called_once()
142 build_project_list_test.project_two.create.assert_not_called()
143 build_project_list_test.project_three.create.assert_not_called()
144 build_project_list_test.project_four.create.assert_not_called()
147def test_build(build_project_list_test, tmp_path):
148 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"])
149 assert project_list.build(
150 projects_path=tmp_path / "projects_path",
151 num_parallel_builds=2,
152 num_threads_per_build=4,
153 other_build_argument=True,
154 )
156 build_project_list_test.project_one.build.assert_called_once_with(
157 project_path=tmp_path / "projects_path" / "one" / "project",
158 output_path=tmp_path / "projects_path" / "one",
159 num_threads=4,
160 other_build_argument=True,
161 )
164def test_build_fail_should_return_false(build_project_list_test, tmp_path):
165 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"])
166 build_project_list_test.project_one.build.return_value = MagicMock(spec=BuildResult)
167 build_project_list_test.project_one.build.return_value.success = False
169 assert not project_list.build(
170 projects_path=tmp_path / "projects_path",
171 num_parallel_builds=2,
172 num_threads_per_build=4,
173 other_build_argument=True,
174 )
177def test_build_with_output_path(build_project_list_test, tmp_path):
178 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"])
179 assert project_list.build(
180 projects_path=tmp_path / "projects_path",
181 num_parallel_builds=2,
182 num_threads_per_build=4,
183 output_path=tmp_path / "output_path",
184 )
186 build_project_list_test.project_one.build.assert_called_once_with(
187 project_path=tmp_path / "projects_path" / "one" / "project",
188 output_path=tmp_path / "output_path" / "one",
189 num_threads=4,
190 )
193def test_build_with_collect_artifacts(build_project_list_test, tmp_path):
194 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"])
195 collect_artifacts = MagicMock()
196 assert project_list.build(
197 projects_path=tmp_path / "projects_path",
198 num_parallel_builds=2,
199 num_threads_per_build=4,
200 collect_artifacts=collect_artifacts,
201 )
203 collect_artifacts.assert_called_once_with(
204 project=build_project_list_test.project_one,
205 output_path=tmp_path / "projects_path" / "one",
206 )
209def test_build_with_collect_artifacts_and_output_path(build_project_list_test, tmp_path):
210 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"])
211 collect_artifacts = MagicMock()
212 assert project_list.build(
213 projects_path=tmp_path / "projects_path",
214 num_parallel_builds=2,
215 num_threads_per_build=4,
216 output_path=tmp_path / "output_path",
217 collect_artifacts=collect_artifacts,
218 )
220 collect_artifacts.assert_called_once_with(
221 project=build_project_list_test.project_one,
222 output_path=tmp_path / "output_path" / "one",
223 )
226def test_build_with_collect_artifacts_return_false_should_fail_build(
227 build_project_list_test, tmp_path
228):
229 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"])
230 collect_artifacts = MagicMock()
231 collect_artifacts.return_value = False
232 assert not project_list.build(
233 projects_path=tmp_path / "projects_path",
234 num_parallel_builds=2,
235 num_threads_per_build=4,
236 collect_artifacts=collect_artifacts,
237 )
240def test_open(build_project_list_test, tmp_path):
241 project_list = BuildProjectList(
242 build_project_list_test.modules, project_filters=[], include_netlist_not_top_builds=True
243 )
244 assert project_list.open(projects_path=tmp_path / "projects_path")
246 build_project_list_test.project_three.open.assert_called_once_with(
247 project_path=tmp_path / "projects_path" / "three" / "project"
248 )
249 build_project_list_test.project_four.open.assert_called_once_with(
250 project_path=tmp_path / "projects_path" / "four" / "project"
251 )
252 build_project_list_test.project_one.open.assert_not_called()
253 build_project_list_test.project_two.open.assert_not_called()