Coverage for tests/unit_tests/commands/test_apio_api.py: 100%
163 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 03:53 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 03:53 +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_text(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_text(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_text(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-commands -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_text(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_packages(apio_runner: ApioRunner):
148 """Test "apio api get-packages" """
150 with apio_runner.in_sandbox() as sb:
152 # -- Execute "apio api get-packages -t xyz" (stdout)
153 result = sb.invoke_apio_cmd(apio, ["api", "get-packages", "-t", "xyz"])
154 sb.assert_result_ok(result)
155 assert '"packages":' in result.output
156 assert '"oss-cad-suite":' in result.output
158 # -- Execute "apio api get-packages -t xyz -o <dir>" (file)
159 path = sb.proj_dir / "apio.json"
160 result = sb.invoke_apio_cmd(
161 apio, ["api", "get-packages", "-t", "xyz", "-o", str(path)]
162 )
163 sb.assert_result_ok(result)
165 # -- Read and verify the file.
166 text = sb.read_file_text(path)
167 data = json.loads(text)
168 assert data["timestamp"] == "xyz"
169 assert (
170 "yosys-release-tag"
171 in data["packages"]["oss-cad-suite"]["build-info"]
172 )
175def test_apio_api_get_system(apio_runner: ApioRunner):
176 """Test "apio api get-system" """
178 with apio_runner.in_sandbox() as sb:
180 # -- Execute "apio api get-system -t xyz" (stdout)
181 result = sb.invoke_apio_cmd(apio, ["api", "get-system", "-t", "xyz"])
182 sb.assert_result_ok(result)
183 assert "xyz" in result.output
184 assert '"apio-cli-version"' in result.output
185 assert '"python-version"' in result.output
187 # -- Execute "apio api get-system -t xyz -o <dir>" (file)
188 path = sb.proj_dir / "apio.json"
189 result = sb.invoke_apio_cmd(
190 apio, ["api", "get-system", "-t", "xyz", "-o", str(path)]
191 )
192 sb.assert_result_ok(result)
194 # -- Read and verify the file.
195 text = sb.read_file_text(path)
196 data = json.loads(text)
197 assert data["timestamp"] == "xyz"
198 assert data["system"]["remote-config-url"].endswith(".jsonc")
201def test_apio_api_get_project(apio_runner: ApioRunner):
202 """Test "apio api get-project" """
204 with apio_runner.in_sandbox() as sb:
206 # -- Create a fake apio project
207 sb.write_default_apio_ini()
209 sb.write_file("synth0.v", "")
210 sb.write_file("tb_0.sv", "")
212 os.makedirs("src1")
213 sb.write_file("src1/synth1.sv", "")
214 sb.write_file("src1/synth2.sv", "")
215 sb.write_file("src1/tb1_tb.sv", "")
217 # -- Execute "apio api get-project -t xyz" (stdout)
218 result = sb.invoke_apio_cmd(apio, ["api", "get-project", "-t", "xyz"])
219 sb.assert_result_ok(result)
220 assert '"default"' in result.output
221 assert '"envs"' in result.output
223 # -- Execute "apio api get-project -t xyz -o <dir>" (file)
224 path = sb.proj_dir / "apio.json"
225 result = sb.invoke_apio_cmd(
226 apio, ["api", "get-project", "-t", "xyz", "-o", str(path)]
227 )
228 sb.assert_result_ok(result)
230 # -- Read and verify the file.
231 text = sb.read_file_text(path)
232 data = json.loads(text)
234 print("\nActual data:")
235 print(json.dumps(data, indent=2))
236 print()
238 assert data == {
239 "timestamp": "xyz",
240 "project": {
241 "active-env": {
242 "name": "default",
243 "options": {
244 "board": "alhambra-ii",
245 "top-module": "main",
246 },
247 },
248 "envs": [
249 "default",
250 ],
251 "synth-files": [
252 "synth0.v",
253 "tb_0.sv",
254 f"src1{os.sep}synth1.sv",
255 f"src1{os.sep}synth2.sv",
256 ],
257 "test-benches": [
258 f"src1{os.sep}tb1_tb.sv",
259 ],
260 "board": {
261 "id": "alhambra-ii",
262 "is-custom": False,
263 "definition": {
264 "description": "Alhambra II",
265 "fpga-id": "ice40hx4k-tq144-8k",
266 "programmer": {
267 "id": "openfpgaloader",
268 "extra-args": "-b ice40_generic --vid ${VID} "
269 + "--pid ${PID} --busdev-num ${BUS}:${DEV}",
270 },
271 "usb": {
272 "vid": "0403",
273 "pid": "6010",
274 "product-regex": "^Alhambra II.*",
275 },
276 },
277 },
278 "fpga": {
279 "id": "ice40hx4k-tq144-8k",
280 "is-custom": False,
281 "definition": {
282 "part-num": "ICE40HX4K-TQ144",
283 "arch": "ice40",
284 "size": "8k",
285 "ice40-params": {
286 "type": "hx8k",
287 "package": "tq144:4k",
288 },
289 },
290 },
291 "programmer": {
292 "id": "openfpgaloader",
293 "is-custom": False,
294 "definition": {
295 "command": "openFPGALoader",
296 "args": "--force-terminal-mode --verify",
297 },
298 },
299 },
300 }
303def test_apio_api_get_build_report(apio_runner: ApioRunner):
304 """Test "apio api get-project" """
306 with apio_runner.in_sandbox() as sb:
308 # -- Execute "apio examples fetch alhambra-ii/blinky"
309 result = sb.invoke_apio_cmd(
310 apio, ["examples", "fetch", "alhambra-ii/blinky"]
311 )
312 sb.assert_result_ok(result)
314 # -- Execute "apio build"
315 result = sb.invoke_apio_cmd(apio, ["build"])
316 sb.assert_result_ok(result)
318 # -- Execute "apio api get-build-report -t xyz" (stdout)
319 result = sb.invoke_apio_cmd(
320 apio, ["api", "get-build-report", "-t", "xyz"]
321 )
322 sb.assert_result_ok(result)
324 # -- Sanity check the output
325 assert '"env": "default"' in result.output
326 assert '"ICESTORM_LC":' in result.output
327 assert '"CLK":' in result.output
328 assert '"fmax_mhz":' in result.output
330 # -- Execute "apio api get-build-report -t xyz -o <dir>" (file)
331 path = sb.proj_dir / "apio.json"
332 result = sb.invoke_apio_cmd(
333 apio, ["api", "get-build-report", "-t", "xyz", "-o", str(path)]
334 )
335 sb.assert_result_ok(result)
337 # -- Read and sanity check the file.
338 text = sb.read_file_text(path)
339 data = json.loads(text)
340 print(data)
342 assert data["timestamp"] == "xyz"
343 assert data["build-report"]["env"] == "default"
344 assert (
345 data["build-report"]["resources"]["ICESTORM_LC"]["available"]
346 == 7680
347 )
348 assert "fmax_mhz" in data["build-report"]["clocks"]["CLK"]
351def test_apio_api_get_examples(apio_runner: ApioRunner):
352 """Test "apio api get-examples" """
354 with apio_runner.in_sandbox() as sb:
356 # -- Execute "apio api get-examples -t xyz" (stdout)
357 result = sb.invoke_apio_cmd(apio, ["api", "get-examples", "-t", "xyz"])
358 sb.assert_result_ok(result)
359 assert "xyz" in result.output
360 assert '"alhambra-ii"' in result.output
361 assert '"blinky"' in result.output
363 # -- Execute "apio api get-examples -t xyz -s boards -o <dir>" (file)
364 path = sb.proj_dir / "apio.json"
365 result = sb.invoke_apio_cmd(
366 apio, ["api", "get-examples", "-t", "xyz", "-o", str(path)]
367 )
368 sb.assert_result_ok(result)
370 # -- Read and verify the file.
371 text = sb.read_file_text(path)
372 data = json.loads(text)
373 assert data["timestamp"] == "xyz"
374 assert (
375 data["examples"]["alhambra-ii"]["blinky"]["description"]
376 == "Blinking led"
377 )
380def test_apio_api_scan_devices(apio_runner: ApioRunner):
381 """Test "apio api scan-devices" """
383 with apio_runner.in_sandbox() as sb:
385 # -- Execute "apio api scan-devices -t xyz". We run it in a
386 # -- subprocess such that it releases the libusb1 file it uses.
387 # -- This also means that it's not included in the pytest test
388 # -- coverage report.
389 result = sb.invoke_apio_cmd(
390 apio, ["api", "scan-devices", "-t", "xyz"], in_subprocess=True
391 )
392 sb.assert_result_ok(result)
394 assert "xyz" in result.output
395 assert "usb-devices" in result.output
396 assert "serial-devices" in result.output
398 # -- Execute "apio api get-boards -t xyz -s boards -o <dir>" (file)
399 path = sb.proj_dir / "apio.json"
401 result = sb.invoke_apio_cmd(
402 apio,
403 ["api", "scan-devices", "-t", "xyz", "-o", str(path)],
404 in_subprocess=True,
405 )
406 sb.assert_result_ok(result)
408 # -- Read and verify the output file. Since we don't know what
409 # -- devices the platform has, we just check for the section keys.
410 text = sb.read_file_text(path)
411 data = json.loads(text)
412 assert data["timestamp"] == "xyz"
413 assert "usb-devices" in data
414 assert "serial-devices" in data
417def test_apio_api_echo(apio_runner: ApioRunner):
418 """Test "apio api echo" """
420 with apio_runner.in_sandbox() as sb:
422 # -- Execute "apio api scan-devices -t xyz". We run it in a
423 # -- subprocess such that it releases the libusb1 file it uses.
424 # -- This also means that it's not included in the pytest test
425 # -- coverage report.
426 result = sb.invoke_apio_cmd(
427 apio,
428 ["api", "echo", "-t", "Hello world", "-s", "OK"],
429 in_subprocess=True,
430 )
431 sb.assert_result_ok(result)
433 assert "Hello world" in result.output