Coverage for tsfpga/test/test_build_project_list.py: 100%

101 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-20 20:52 +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# -------------------------------------------------------------------------------------------------- 

8 

9# Standard libraries 

10from unittest.mock import MagicMock 

11 

12# Third party libraries 

13import pytest 

14 

15# First party libraries 

16from tsfpga.build_project_list import BuildProjectList 

17from tsfpga.module import BaseModule 

18from tsfpga.system_utils import create_directory 

19from tsfpga.vivado.project import BuildResult, VivadoProject 

20 

21 

22@pytest.fixture 

23def build_project_list_test(): 

24 # pylint: disable=too-many-instance-attributes 

25 class TestBuildProjectList: 

26 @staticmethod 

27 def _get_mocks(name, is_netlist_build): 

28 project = MagicMock(spec=VivadoProject) 

29 project.name = name 

30 project.__str__.return_value = f"MockProject {name}" 

31 project.is_netlist_build = is_netlist_build 

32 

33 module = MagicMock(spec=BaseModule) 

34 module.name = name 

35 module.get_build_projects.return_value = [project] 

36 

37 return module, project 

38 

39 def __init__(self): 

40 self.module_one, self.project_one = self._get_mocks("one", False) 

41 self.module_two, self.project_two = self._get_mocks("two", False) 

42 

43 self.module_three, self.project_three = self._get_mocks("three", True) 

44 self.module_four, self.project_four = self._get_mocks("four", True) 

45 

46 self.modules = [self.module_one, self.module_two, self.module_three, self.module_four] 

47 

48 return TestBuildProjectList() 

49 

50 

51# False positive for pytest fixtures 

52# pylint: disable=redefined-outer-name 

53 

54 

55def test_can_list_without_error(build_project_list_test): 

56 list_str = str(BuildProjectList(build_project_list_test.modules, project_filters=[])) 

57 assert "one" in list_str 

58 assert "two" in list_str 

59 

60 

61def test_project_filtering(build_project_list_test): 

62 project_list = BuildProjectList(build_project_list_test.modules, project_filters=[]) 

63 assert len(project_list.projects) == 2 

64 assert build_project_list_test.project_one in project_list.projects 

65 assert build_project_list_test.project_two in project_list.projects 

66 

67 project_list = BuildProjectList( 

68 build_project_list_test.modules, project_filters=["apa", "*ne", "three", "four"] 

69 ) 

70 assert len(project_list.projects) == 1 

71 assert build_project_list_test.project_one in project_list.projects 

72 

73 project_list = BuildProjectList( 

74 build_project_list_test.modules, project_filters=["one", "one", "on*"] 

75 ) 

76 assert len(project_list.projects) == 1 

77 assert build_project_list_test.project_one in project_list.projects 

78 

79 project_list = BuildProjectList( 

80 build_project_list_test.modules, project_filters=[], include_netlist_not_top_builds=True 

81 ) 

82 assert len(project_list.projects) == 2 

83 assert build_project_list_test.project_three in project_list.projects 

84 assert build_project_list_test.project_four in project_list.projects 

85 

86 project_list = BuildProjectList( 

87 build_project_list_test.modules, 

88 include_netlist_not_top_builds=True, 

89 project_filters=["apa", "one", "two", "thr*"], 

90 ) 

91 assert len(project_list.projects) == 1 

92 assert build_project_list_test.project_three in project_list.projects 

93 

94 

95def test_create(build_project_list_test, tmp_path): 

96 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one", "two"]) 

97 assert project_list.create( 

98 projects_path=tmp_path / "projects_path", 

99 num_parallel_builds=2, 

100 ip_cache_path=tmp_path / "ip_cache_path", 

101 ) 

102 

103 build_project_list_test.project_one.create.assert_called_once_with( 

104 project_path=tmp_path / "projects_path" / "one" / "project", 

105 ip_cache_path=tmp_path / "ip_cache_path", 

106 ) 

107 

108 build_project_list_test.project_two.create.assert_called_once_with( 

109 project_path=tmp_path / "projects_path" / "two" / "project", 

110 ip_cache_path=tmp_path / "ip_cache_path", 

111 ) 

112 

113 build_project_list_test.project_three.create.assert_not_called() 

114 build_project_list_test.project_four.create.assert_not_called() 

115 

116 

117def test_create_unless_exists(build_project_list_test, tmp_path): 

118 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"]) 

119 assert project_list.create_unless_exists( 

120 projects_path=tmp_path / "projects_path", 

121 num_parallel_builds=2, 

122 ip_cache_path=tmp_path / "ip_cache_path", 

123 ) 

124 

125 build_project_list_test.project_one.create.assert_called_once_with( 

126 project_path=tmp_path / "projects_path" / "one" / "project", 

127 ip_cache_path=tmp_path / "ip_cache_path", 

128 ) 

129 

130 # Create project file manually 

131 create_directory(tmp_path / "projects_path" / "one" / "project") 

132 (tmp_path / "projects_path" / "one" / "project" / "one.xpr").write_text("") 

133 

134 assert project_list.create_unless_exists( 

135 projects_path=tmp_path / "projects_path", 

136 num_parallel_builds=2, 

137 ip_cache_path=tmp_path / "ip_cache_path", 

138 ) 

139 

140 # Still only called once after second create_unless_exists() 

141 build_project_list_test.project_one.create.assert_called_once() 

142 

143 build_project_list_test.project_two.create.assert_not_called() 

144 build_project_list_test.project_three.create.assert_not_called() 

145 build_project_list_test.project_four.create.assert_not_called() 

146 

147 

148def test_build(build_project_list_test, tmp_path): 

149 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"]) 

150 assert project_list.build( 

151 projects_path=tmp_path / "projects_path", 

152 num_parallel_builds=2, 

153 num_threads_per_build=4, 

154 other_build_argument=True, 

155 ) 

156 

157 build_project_list_test.project_one.build.assert_called_once_with( 

158 project_path=tmp_path / "projects_path" / "one" / "project", 

159 output_path=tmp_path / "projects_path" / "one", 

160 num_threads=4, 

161 other_build_argument=True, 

162 ) 

163 

164 

165def test_build_fail_should_return_false(build_project_list_test, tmp_path): 

166 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"]) 

167 build_project_list_test.project_one.build.return_value = MagicMock(spec=BuildResult) 

168 build_project_list_test.project_one.build.return_value.success = False 

169 

170 assert not project_list.build( 

171 projects_path=tmp_path / "projects_path", 

172 num_parallel_builds=2, 

173 num_threads_per_build=4, 

174 other_build_argument=True, 

175 ) 

176 

177 

178def test_build_with_output_path(build_project_list_test, tmp_path): 

179 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"]) 

180 assert project_list.build( 

181 projects_path=tmp_path / "projects_path", 

182 num_parallel_builds=2, 

183 num_threads_per_build=4, 

184 output_path=tmp_path / "output_path", 

185 ) 

186 

187 build_project_list_test.project_one.build.assert_called_once_with( 

188 project_path=tmp_path / "projects_path" / "one" / "project", 

189 output_path=tmp_path / "output_path" / "one", 

190 num_threads=4, 

191 ) 

192 

193 

194def test_build_with_collect_artifacts(build_project_list_test, tmp_path): 

195 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"]) 

196 collect_artifacts = MagicMock() 

197 assert project_list.build( 

198 projects_path=tmp_path / "projects_path", 

199 num_parallel_builds=2, 

200 num_threads_per_build=4, 

201 collect_artifacts=collect_artifacts, 

202 ) 

203 

204 collect_artifacts.assert_called_once_with( 

205 project=build_project_list_test.project_one, 

206 output_path=tmp_path / "projects_path" / "one", 

207 ) 

208 

209 

210def test_build_with_collect_artifacts_and_output_path(build_project_list_test, tmp_path): 

211 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"]) 

212 collect_artifacts = MagicMock() 

213 assert project_list.build( 

214 projects_path=tmp_path / "projects_path", 

215 num_parallel_builds=2, 

216 num_threads_per_build=4, 

217 output_path=tmp_path / "output_path", 

218 collect_artifacts=collect_artifacts, 

219 ) 

220 

221 collect_artifacts.assert_called_once_with( 

222 project=build_project_list_test.project_one, 

223 output_path=tmp_path / "output_path" / "one", 

224 ) 

225 

226 

227def test_build_with_collect_artifacts_return_false_should_fail_build( 

228 build_project_list_test, tmp_path 

229): 

230 project_list = BuildProjectList(build_project_list_test.modules, project_filters=["one"]) 

231 collect_artifacts = MagicMock() 

232 collect_artifacts.return_value = False 

233 assert not project_list.build( 

234 projects_path=tmp_path / "projects_path", 

235 num_parallel_builds=2, 

236 num_threads_per_build=4, 

237 collect_artifacts=collect_artifacts, 

238 ) 

239 

240 

241def test_open(build_project_list_test, tmp_path): 

242 project_list = BuildProjectList( 

243 build_project_list_test.modules, project_filters=[], include_netlist_not_top_builds=True 

244 ) 

245 assert project_list.open(projects_path=tmp_path / "projects_path") 

246 

247 build_project_list_test.project_three.open.assert_called_once_with( 

248 project_path=tmp_path / "projects_path" / "three" / "project" 

249 ) 

250 build_project_list_test.project_four.open.assert_called_once_with( 

251 project_path=tmp_path / "projects_path" / "four" / "project" 

252 ) 

253 build_project_list_test.project_one.open.assert_not_called() 

254 build_project_list_test.project_two.open.assert_not_called()