Coverage for tests / unit_tests / commands / test_apio_api.py: 100%

125 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-25 02:31 +0000

1"""Test for the "apio api" command.""" 

2 

3# NOTE: 'apio api scan-devices' require apio packages (for libusb1 lib) 

4# and thus, is tested in the integration tests. 

5 

6import json 

7import os 

8from tests.conftest import ApioRunner 

9from apio.commands.apio import apio_top_cli as apio 

10 

11# TODO: Add more tests 

12 

13 

14def test_apio_api_get_boards(apio_runner: ApioRunner): 

15 """Test "apio api get-boards" """ 

16 

17 with apio_runner.in_sandbox() as sb: 

18 

19 # -- Execute "apio api get-boards -t xyz" (stdout) 

20 result = sb.invoke_apio_cmd(apio, ["api", "get-boards", "-t", "xyz"]) 

21 sb.assert_result_ok(result) 

22 assert "xyz" in result.output 

23 assert "alhambra-ii" in result.output 

24 

25 # -- Execute "apio api get-boards -t xyz -o <dir>" (file) 

26 path = sb.proj_dir / "apio.json" 

27 result = sb.invoke_apio_cmd( 

28 apio, ["api", "get-boards", "-t", "xyz", "-o", str(path)] 

29 ) 

30 sb.assert_result_ok(result) 

31 

32 # -- Read and verify the file. 

33 text = sb.read_file(path) 

34 data = json.loads(text) 

35 assert data["timestamp"] == "xyz" 

36 assert data["boards"]["alhambra-ii"] == { 

37 "description": "Alhambra II", 

38 "fpga": { 

39 "id": "ice40hx4k-tq144-8k", 

40 "part-num": "ICE40HX4K-TQ144", 

41 "arch": "ice40", 

42 "size": "8k", 

43 "ice40-params": { 

44 "package": "tq144:4k", 

45 "type": "hx8k", 

46 }, 

47 }, 

48 "programmer": {"id": "openfpgaloader"}, 

49 } 

50 

51 

52def test_apio_api_get_fpgas(apio_runner: ApioRunner): 

53 """Test "apio api get-fpgas" """ 

54 

55 with apio_runner.in_sandbox() as sb: 

56 

57 # -- Execute "apio api get-fpgas -t xyz" (stdout) 

58 result = sb.invoke_apio_cmd(apio, ["api", "get-fpgas", "-t", "xyz"]) 

59 sb.assert_result_ok(result) 

60 assert "xyz" in result.output 

61 assert "ice40hx4k-tq144-8k" in result.output 

62 

63 # -- Execute "apio api get-fpgas -t xyz -o <dir>" (file) 

64 path = sb.proj_dir / "apio.json" 

65 result = sb.invoke_apio_cmd( 

66 apio, ["api", "get-fpgas", "-t", "xyz", "-o", str(path)] 

67 ) 

68 sb.assert_result_ok(result) 

69 

70 # -- Read and verify the file. 

71 text = sb.read_file(path) 

72 data = json.loads(text) 

73 assert data["timestamp"] == "xyz" 

74 assert data["fpgas"]["ice40hx4k-tq144-8k"] == { 

75 "part-num": "ICE40HX4K-TQ144", 

76 "arch": "ice40", 

77 "size": "8k", 

78 "ice40-params": { 

79 "package": "tq144:4k", 

80 "type": "hx8k", 

81 }, 

82 } 

83 

84 

85def test_apio_api_get_programmers(apio_runner: ApioRunner): 

86 """Test "apio api get-programmers" """ 

87 

88 with apio_runner.in_sandbox() as sb: 

89 

90 # -- Execute "apio api get-programmers -t xyz" (stdout) 

91 result = sb.invoke_apio_cmd( 

92 apio, ["api", "get-programmers", "-t", "xyz"] 

93 ) 

94 sb.assert_result_ok(result) 

95 assert "xyz" in result.output 

96 assert "openfpgaloader" in result.output 

97 

98 # -- Execute "apio api get-programmers -t xyz -o <dir>" (file) 

99 path = sb.proj_dir / "apio.json" 

100 result = sb.invoke_apio_cmd( 

101 apio, ["api", "get-programmers", "-t", "xyz", "-o", str(path)] 

102 ) 

103 sb.assert_result_ok(result) 

104 

105 # -- Read and verify the file. 

106 text = sb.read_file(path) 

107 data = json.loads(text) 

108 assert data["timestamp"] == "xyz" 

109 assert data["programmers"]["openfpgaloader"] == { 

110 "command": "openFPGALoader", 

111 "args": "", 

112 } 

113 

114 

115def test_apio_api_get_commands(apio_runner: ApioRunner): 

116 """Test "apio api get-commands" """ 

117 

118 with apio_runner.in_sandbox() as sb: 

119 

120 # -- Execute "apio api get-commands -t xyz" (stdout) 

121 result = sb.invoke_apio_cmd(apio, ["api", "get-commands", "-t", "xyz"]) 

122 sb.assert_result_ok(result) 

123 assert "xyz" in result.output 

124 assert '"apio"' in result.output 

125 assert '"api"' in result.output 

126 assert '"get-boards"' in result.output 

127 

128 # -- Execute "apio api get-boards -t xyz -o <dir>" (file) 

129 path = sb.proj_dir / "apio.json" 

130 result = sb.invoke_apio_cmd( 

131 apio, ["api", "get-commands", "-t", "xyz", "-o", str(path)] 

132 ) 

133 sb.assert_result_ok(result) 

134 

135 # -- Read and verify the file. 

136 text = sb.read_file(path) 

137 data = json.loads(text) 

138 assert data["timestamp"] == "xyz" 

139 assert ( 

140 data["commands"]["apio"]["commands"]["api"]["commands"][ 

141 "get-boards" 

142 ] 

143 == {} 

144 ) 

145 

146 

147def test_apio_api_get_system(apio_runner: ApioRunner): 

148 """Test "apio api get-system" """ 

149 

150 with apio_runner.in_sandbox() as sb: 

151 

152 # -- Execute "apio api get-system -t xyz" (stdout) 

153 result = sb.invoke_apio_cmd(apio, ["api", "get-system", "-t", "xyz"]) 

154 sb.assert_result_ok(result) 

155 assert "xyz" in result.output 

156 assert '"apio-cli-version"' in result.output 

157 assert '"python-version"' in result.output 

158 

159 # -- Execute "apio api get-system -t xyz -o <dir>" (file) 

160 path = sb.proj_dir / "apio.json" 

161 result = sb.invoke_apio_cmd( 

162 apio, ["api", "get-system", "-t", "xyz", "-o", str(path)] 

163 ) 

164 sb.assert_result_ok(result) 

165 

166 # -- Read and verify the file. 

167 text = sb.read_file(path) 

168 data = json.loads(text) 

169 assert data["timestamp"] == "xyz" 

170 assert data["system"]["remote-config-url"].endswith(".jsonc") 

171 

172 

173def test_apio_api_get_project(apio_runner: ApioRunner): 

174 """Test "apio api get-project" """ 

175 

176 with apio_runner.in_sandbox() as sb: 

177 

178 # -- Create a fake apio project 

179 sb.write_default_apio_ini() 

180 

181 sb.write_file("synth0.v", "") 

182 sb.write_file("tb_0.sv", "") 

183 

184 os.makedirs("src1") 

185 sb.write_file("src1/synth1.sv", "") 

186 sb.write_file("src1/synth2.sv", "") 

187 sb.write_file("src1/tb1_tb.sv", "") 

188 

189 # -- Execute "apio api get-project -t xyz" (stdout) 

190 result = sb.invoke_apio_cmd(apio, ["api", "get-project", "-t", "xyz"]) 

191 sb.assert_result_ok(result) 

192 assert '"default"' in result.output 

193 assert '"envs"' in result.output 

194 

195 # -- Execute "apio api get-project -t xyz -o <dir>" (file) 

196 path = sb.proj_dir / "apio.json" 

197 result = sb.invoke_apio_cmd( 

198 apio, ["api", "get-project", "-t", "xyz", "-o", str(path)] 

199 ) 

200 sb.assert_result_ok(result) 

201 

202 # -- Read and verify the file. 

203 text = sb.read_file(path) 

204 data = json.loads(text) 

205 

206 assert data == { 

207 "timestamp": "xyz", 

208 "project": { 

209 "active-env": { 

210 "name": "default", 

211 "options": { 

212 "board": "alhambra-ii", 

213 "top-module": "main", 

214 }, 

215 }, 

216 "envs": [ 

217 "default", 

218 ], 

219 "synth-files": [ 

220 "synth0.v", 

221 "tb_0.sv", 

222 f"src1{os.sep}synth1.sv", 

223 f"src1{os.sep}synth2.sv", 

224 ], 

225 "test-benches": [ 

226 f"src1{os.sep}tb1_tb.sv", 

227 ], 

228 "board": { 

229 "id": "alhambra-ii", 

230 "description": "Alhambra II", 

231 "fpga-id": "ice40hx4k-tq144-8k", 

232 "programmer": { 

233 "extra-args": "--verify -b ice40_generic" 

234 + " --vid ${VID} --pid ${PID} " 

235 "--busdev-num ${BUS}:${DEV}", 

236 "id": "openfpgaloader", 

237 }, 

238 "usb": { 

239 "pid": "6010", 

240 "product-regex": "^Alhambra II.*", 

241 "vid": "0403", 

242 }, 

243 }, 

244 "fpga": { 

245 "id": "ice40hx4k-tq144-8k", 

246 "arch": "ice40", 

247 "part-num": "ICE40HX4K-TQ144", 

248 "size": "8k", 

249 "ice40-params": { 

250 "package": "tq144:4k", 

251 "type": "hx8k", 

252 }, 

253 }, 

254 "programmer": { 

255 "id": "openfpgaloader", 

256 "args": "", 

257 "command": "openFPGALoader", 

258 }, 

259 }, 

260 } 

261 

262 

263def test_apio_api_get_examples(apio_runner: ApioRunner): 

264 """Test "apio api get-examples" """ 

265 

266 with apio_runner.in_sandbox() as sb: 

267 

268 # -- Execute "apio api get-examples -t xyz" (stdout) 

269 result = sb.invoke_apio_cmd(apio, ["api", "get-examples", "-t", "xyz"]) 

270 sb.assert_result_ok(result) 

271 assert "xyz" in result.output 

272 assert '"alhambra-ii"' in result.output 

273 assert '"blinky"' in result.output 

274 

275 # -- Execute "apio api get-examples -t xyz -s boards -o <dir>" (file) 

276 path = sb.proj_dir / "apio.json" 

277 result = sb.invoke_apio_cmd( 

278 apio, ["api", "get-examples", "-t", "xyz", "-o", str(path)] 

279 ) 

280 sb.assert_result_ok(result) 

281 

282 # -- Read and verify the file. 

283 text = sb.read_file(path) 

284 data = json.loads(text) 

285 assert data["timestamp"] == "xyz" 

286 assert ( 

287 data["examples"]["alhambra-ii"]["blinky"]["description"] 

288 == "Blinking led" 

289 ) 

290 

291 

292def test_apio_api_scan_devices(apio_runner: ApioRunner): 

293 """Test "apio api scan-devices" """ 

294 

295 with apio_runner.in_sandbox() as sb: 

296 

297 # -- Execute "apio api scan-devices -t xyz". We run it in a 

298 # -- subprocess such that it releases the libusb1 file it uses. 

299 # -- This also means that it's not included in the pytest test 

300 # -- coverage report. 

301 result = sb.invoke_apio_cmd( 

302 apio, ["api", "scan-devices", "-t", "xyz"], in_subprocess=True 

303 ) 

304 sb.assert_result_ok(result) 

305 

306 assert "xyz" in result.output 

307 assert "usb-devices" in result.output 

308 assert "serial-devices" in result.output 

309 

310 # -- Execute "apio api get-boards -t xyz -s boards -o <dir>" (file) 

311 path = sb.proj_dir / "apio.json" 

312 

313 result = sb.invoke_apio_cmd( 

314 apio, 

315 ["api", "scan-devices", "-t", "xyz", "-o", str(path)], 

316 in_subprocess=True, 

317 ) 

318 sb.assert_result_ok(result) 

319 

320 # -- Read and verify the output file. Since we don't know what 

321 # -- devices the platform has, we just check for the section keys. 

322 text = sb.read_file(path) 

323 data = json.loads(text) 

324 assert data["timestamp"] == "xyz" 

325 assert "usb-devices" in data 

326 assert "serial-devices" in data 

327 

328 

329def test_apio_api_echo(apio_runner: ApioRunner): 

330 """Test "apio api echo" """ 

331 

332 with apio_runner.in_sandbox() as sb: 

333 

334 # -- Execute "apio api scan-devices -t xyz". We run it in a 

335 # -- subprocess such that it releases the libusb1 file it uses. 

336 # -- This also means that it's not included in the pytest test 

337 # -- coverage report. 

338 result = sb.invoke_apio_cmd( 

339 apio, 

340 ["api", "echo", "-t", "Hello world", "-s", "OK"], 

341 in_subprocess=True, 

342 ) 

343 sb.assert_result_ok(result) 

344 

345 assert "Hello world" in result.output