Coverage for tests/unit_tests/commands/test_apio_api.py: 100%
147 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 01:55 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 01:55 +0000
1"""Test for the "apio api" command."""
3# NOTE: 'apio api scan-devices' require apio packages (for libusb1 lib)
4# and thus, is tested in the integration tests.
6import json
7import os
8from tests.conftest import ApioRunner
9from apio.commands.apio import apio_top_cli as apio
11# TODO: Add more tests
14def test_apio_api_get_boards(apio_runner: ApioRunner):
15 """Test "apio api get-boards" """
17 with apio_runner.in_sandbox() as sb:
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
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)
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 }
52def test_apio_api_get_fpgas(apio_runner: ApioRunner):
53 """Test "apio api get-fpgas" """
55 with apio_runner.in_sandbox() as sb:
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
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)
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 }
85def test_apio_api_get_programmers(apio_runner: ApioRunner):
86 """Test "apio api get-programmers" """
88 with apio_runner.in_sandbox() as sb:
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
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)
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": "--force-terminal-mode --verify",
112 }
115def test_apio_api_get_commands(apio_runner: ApioRunner):
116 """Test "apio api get-commands" """
118 with apio_runner.in_sandbox() as sb:
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
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)
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 )
147def test_apio_api_get_system(apio_runner: ApioRunner):
148 """Test "apio api get-system" """
150 with apio_runner.in_sandbox() as sb:
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
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)
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")
173def test_apio_api_get_project(apio_runner: ApioRunner):
174 """Test "apio api get-project" """
176 with apio_runner.in_sandbox() as sb:
178 # -- Create a fake apio project
179 sb.write_default_apio_ini()
181 sb.write_file("synth0.v", "")
182 sb.write_file("tb_0.sv", "")
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", "")
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
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)
202 # -- Read and verify the file.
203 text = sb.read_file(path)
204 data = json.loads(text)
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": "-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": "--force-terminal-mode --verify",
257 "command": "openFPGALoader",
258 },
259 },
260 }
263def test_apio_api_get_build_report(apio_runner: ApioRunner):
264 """Test "apio api get-project" """
266 with apio_runner.in_sandbox() as sb:
268 # -- Execute "apio examples fetch alhambra-ii/blinky"
269 result = sb.invoke_apio_cmd(
270 apio, ["examples", "fetch", "alhambra-ii/blinky"]
271 )
272 sb.assert_result_ok(result)
274 # -- Execute "apio build"
275 result = sb.invoke_apio_cmd(apio, ["build"])
276 sb.assert_result_ok(result)
278 # -- Execute "apio api get-build-report -t xyz" (stdout)
279 result = sb.invoke_apio_cmd(
280 apio, ["api", "get-build-report", "-t", "xyz"]
281 )
282 sb.assert_result_ok(result)
284 # -- Sanity check the output
285 assert '"env": "default"' in result.output
286 assert '"ICESTORM_LC":' in result.output
287 assert '"CLK":' in result.output
288 assert '"fmax_mhz":' in result.output
290 # -- Execute "apio api get-build-report -t xyz -o <dir>" (file)
291 path = sb.proj_dir / "apio.json"
292 result = sb.invoke_apio_cmd(
293 apio, ["api", "get-build-report", "-t", "xyz", "-o", str(path)]
294 )
295 sb.assert_result_ok(result)
297 # -- Read and sanity check the file.
298 text = sb.read_file(path)
299 data = json.loads(text)
300 print(data)
302 assert data["timestamp"] == "xyz"
303 assert data["build-report"]["env"] == "default"
304 assert (
305 data["build-report"]["resources"]["ICESTORM_LC"]["available"]
306 == 7680
307 )
308 assert "fmax_mhz" in data["build-report"]["clocks"]["CLK"]
311def test_apio_api_get_examples(apio_runner: ApioRunner):
312 """Test "apio api get-examples" """
314 with apio_runner.in_sandbox() as sb:
316 # -- Execute "apio api get-examples -t xyz" (stdout)
317 result = sb.invoke_apio_cmd(apio, ["api", "get-examples", "-t", "xyz"])
318 sb.assert_result_ok(result)
319 assert "xyz" in result.output
320 assert '"alhambra-ii"' in result.output
321 assert '"blinky"' in result.output
323 # -- Execute "apio api get-examples -t xyz -s boards -o <dir>" (file)
324 path = sb.proj_dir / "apio.json"
325 result = sb.invoke_apio_cmd(
326 apio, ["api", "get-examples", "-t", "xyz", "-o", str(path)]
327 )
328 sb.assert_result_ok(result)
330 # -- Read and verify the file.
331 text = sb.read_file(path)
332 data = json.loads(text)
333 assert data["timestamp"] == "xyz"
334 assert (
335 data["examples"]["alhambra-ii"]["blinky"]["description"]
336 == "Blinking led"
337 )
340def test_apio_api_scan_devices(apio_runner: ApioRunner):
341 """Test "apio api scan-devices" """
343 with apio_runner.in_sandbox() as sb:
345 # -- Execute "apio api scan-devices -t xyz". We run it in a
346 # -- subprocess such that it releases the libusb1 file it uses.
347 # -- This also means that it's not included in the pytest test
348 # -- coverage report.
349 result = sb.invoke_apio_cmd(
350 apio, ["api", "scan-devices", "-t", "xyz"], in_subprocess=True
351 )
352 sb.assert_result_ok(result)
354 assert "xyz" in result.output
355 assert "usb-devices" in result.output
356 assert "serial-devices" in result.output
358 # -- Execute "apio api get-boards -t xyz -s boards -o <dir>" (file)
359 path = sb.proj_dir / "apio.json"
361 result = sb.invoke_apio_cmd(
362 apio,
363 ["api", "scan-devices", "-t", "xyz", "-o", str(path)],
364 in_subprocess=True,
365 )
366 sb.assert_result_ok(result)
368 # -- Read and verify the output file. Since we don't know what
369 # -- devices the platform has, we just check for the section keys.
370 text = sb.read_file(path)
371 data = json.loads(text)
372 assert data["timestamp"] == "xyz"
373 assert "usb-devices" in data
374 assert "serial-devices" in data
377def test_apio_api_echo(apio_runner: ApioRunner):
378 """Test "apio api echo" """
380 with apio_runner.in_sandbox() as sb:
382 # -- Execute "apio api scan-devices -t xyz". We run it in a
383 # -- subprocess such that it releases the libusb1 file it uses.
384 # -- This also means that it's not included in the pytest test
385 # -- coverage report.
386 result = sb.invoke_apio_cmd(
387 apio,
388 ["api", "echo", "-t", "Hello world", "-s", "OK"],
389 in_subprocess=True,
390 )
391 sb.assert_result_ok(result)
393 assert "Hello world" in result.output