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
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-25 02:31 +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": "",
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": "--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 }
263def test_apio_api_get_examples(apio_runner: ApioRunner):
264 """Test "apio api get-examples" """
266 with apio_runner.in_sandbox() as sb:
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
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)
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 )
292def test_apio_api_scan_devices(apio_runner: ApioRunner):
293 """Test "apio api scan-devices" """
295 with apio_runner.in_sandbox() as sb:
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)
306 assert "xyz" in result.output
307 assert "usb-devices" in result.output
308 assert "serial-devices" in result.output
310 # -- Execute "apio api get-boards -t xyz -s boards -o <dir>" (file)
311 path = sb.proj_dir / "apio.json"
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)
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
329def test_apio_api_echo(apio_runner: ApioRunner):
330 """Test "apio api echo" """
332 with apio_runner.in_sandbox() as sb:
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)
345 assert "Hello world" in result.output