Coverage for tests / unit_tests / commands / test_apio_api.py: 100%
125 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 02:47 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 02:47 +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 },
44 "programmer": {"id": "openfpgaloader"},
45 }
48def test_apio_api_get_fpgas(apio_runner: ApioRunner):
49 """Test "apio api get-fpgas" """
51 with apio_runner.in_sandbox() as sb:
53 # -- Execute "apio api get-fpgas -t xyz" (stdout)
54 result = sb.invoke_apio_cmd(apio, ["api", "get-fpgas", "-t", "xyz"])
55 sb.assert_result_ok(result)
56 assert "xyz" in result.output
57 assert "ice40hx4k-tq144-8k" in result.output
59 # -- Execute "apio api get-fpgas -t xyz -o <dir>" (file)
60 path = sb.proj_dir / "apio.json"
61 result = sb.invoke_apio_cmd(
62 apio, ["api", "get-fpgas", "-t", "xyz", "-o", str(path)]
63 )
64 sb.assert_result_ok(result)
66 # -- Read and verify the file.
67 text = sb.read_file(path)
68 data = json.loads(text)
69 assert data["timestamp"] == "xyz"
70 assert data["fpgas"]["ice40hx4k-tq144-8k"] == {
71 "part-num": "ICE40HX4K-TQ144",
72 "arch": "ice40",
73 "size": "8k",
74 }
77def test_apio_api_get_programmers(apio_runner: ApioRunner):
78 """Test "apio api get-programmers" """
80 with apio_runner.in_sandbox() as sb:
82 # -- Execute "apio api get-programmers -t xyz" (stdout)
83 result = sb.invoke_apio_cmd(
84 apio, ["api", "get-programmers", "-t", "xyz"]
85 )
86 sb.assert_result_ok(result)
87 assert "xyz" in result.output
88 assert "openfpgaloader" in result.output
90 # -- Execute "apio api get-programmers -t xyz -o <dir>" (file)
91 path = sb.proj_dir / "apio.json"
92 result = sb.invoke_apio_cmd(
93 apio, ["api", "get-programmers", "-t", "xyz", "-o", str(path)]
94 )
95 sb.assert_result_ok(result)
97 # -- Read and verify the file.
98 text = sb.read_file(path)
99 data = json.loads(text)
100 assert data["timestamp"] == "xyz"
101 assert data["programmers"]["openfpgaloader"] == {
102 "command": "openFPGALoader",
103 "args": "",
104 }
107def test_apio_api_get_commands(apio_runner: ApioRunner):
108 """Test "apio api get-commands" """
110 with apio_runner.in_sandbox() as sb:
112 # -- Execute "apio api get-commands -t xyz" (stdout)
113 result = sb.invoke_apio_cmd(apio, ["api", "get-commands", "-t", "xyz"])
114 sb.assert_result_ok(result)
115 assert "xyz" in result.output
116 assert '"apio"' in result.output
117 assert '"api"' in result.output
118 assert '"get-boards"' in result.output
120 # -- Execute "apio api get-boards -t xyz -o <dir>" (file)
121 path = sb.proj_dir / "apio.json"
122 result = sb.invoke_apio_cmd(
123 apio, ["api", "get-commands", "-t", "xyz", "-o", str(path)]
124 )
125 sb.assert_result_ok(result)
127 # -- Read and verify the file.
128 text = sb.read_file(path)
129 data = json.loads(text)
130 assert data["timestamp"] == "xyz"
131 assert (
132 data["commands"]["apio"]["commands"]["api"]["commands"][
133 "get-boards"
134 ]
135 == {}
136 )
139def test_apio_api_get_system(apio_runner: ApioRunner):
140 """Test "apio api get-system" """
142 with apio_runner.in_sandbox() as sb:
144 # -- Execute "apio api get-system -t xyz" (stdout)
145 result = sb.invoke_apio_cmd(apio, ["api", "get-system", "-t", "xyz"])
146 sb.assert_result_ok(result)
147 assert "xyz" in result.output
148 assert '"apio-cli-version"' in result.output
149 assert '"python-version"' in result.output
151 # -- Execute "apio api get-system -t xyz -o <dir>" (file)
152 path = sb.proj_dir / "apio.json"
153 result = sb.invoke_apio_cmd(
154 apio, ["api", "get-system", "-t", "xyz", "-o", str(path)]
155 )
156 sb.assert_result_ok(result)
158 # -- Read and verify the file.
159 text = sb.read_file(path)
160 data = json.loads(text)
161 assert data["timestamp"] == "xyz"
162 assert data["system"]["remote-config-url"].endswith(".jsonc")
165def test_apio_api_get_project(apio_runner: ApioRunner):
166 """Test "apio api get-project" """
168 with apio_runner.in_sandbox() as sb:
170 # -- Create a fake apio project
171 sb.write_default_apio_ini()
173 sb.write_file("synth0.v", "")
174 sb.write_file("tb_0.sv", "")
176 os.makedirs("src1")
177 sb.write_file("src1/synth1.sv", "")
178 sb.write_file("src1/synth2.sv", "")
179 sb.write_file("src1/tb1_tb.sv", "")
181 # -- Execute "apio api get-project -t xyz" (stdout)
182 result = sb.invoke_apio_cmd(apio, ["api", "get-project", "-t", "xyz"])
183 sb.assert_result_ok(result)
184 assert '"default"' in result.output
185 assert '"envs"' in result.output
187 # -- Execute "apio api get-project -t xyz -o <dir>" (file)
188 path = sb.proj_dir / "apio.json"
189 result = sb.invoke_apio_cmd(
190 apio, ["api", "get-project", "-t", "xyz", "-o", str(path)]
191 )
192 sb.assert_result_ok(result)
194 # -- Read and verify the file.
195 text = sb.read_file(path)
196 data = json.loads(text)
198 assert data == {
199 "timestamp": "xyz",
200 "project": {
201 "active-env": {
202 "name": "default",
203 "options": {
204 "board": "alhambra-ii",
205 "top-module": "main",
206 },
207 },
208 "envs": [
209 "default",
210 ],
211 "synth-files": [
212 "synth0.v",
213 "tb_0.sv",
214 f"src1{os.sep}synth1.sv",
215 f"src1{os.sep}synth2.sv",
216 ],
217 "test-benches": [
218 f"src1{os.sep}tb1_tb.sv",
219 ],
220 "board": {
221 "id": "alhambra-ii",
222 "description": "Alhambra II",
223 "fpga-id": "ice40hx4k-tq144-8k",
224 "programmer": {
225 "extra-args": "--verify -b ice40_generic"
226 + " --vid ${VID} --pid ${PID} "
227 "--busdev-num ${BUS}:${DEV}",
228 "id": "openfpgaloader",
229 },
230 "usb": {
231 "pid": "6010",
232 "product-regex": "^Alhambra II.*",
233 "vid": "0403",
234 },
235 },
236 "fpga": {
237 "id": "ice40hx4k-tq144-8k",
238 "arch": "ice40",
239 "pack": "tq144:4k",
240 "part-num": "ICE40HX4K-TQ144",
241 "size": "8k",
242 "type": "hx8k",
243 },
244 "programmer": {
245 "id": "openfpgaloader",
246 "args": "",
247 "command": "openFPGALoader",
248 },
249 },
250 }
253def test_apio_api_get_examples(apio_runner: ApioRunner):
254 """Test "apio api get-examples" """
256 with apio_runner.in_sandbox() as sb:
258 # -- Execute "apio api get-examples -t xyz" (stdout)
259 result = sb.invoke_apio_cmd(apio, ["api", "get-examples", "-t", "xyz"])
260 sb.assert_result_ok(result)
261 assert "xyz" in result.output
262 assert '"alhambra-ii"' in result.output
263 assert '"blinky"' in result.output
265 # -- Execute "apio api get-examples -t xyz -s boards -o <dir>" (file)
266 path = sb.proj_dir / "apio.json"
267 result = sb.invoke_apio_cmd(
268 apio, ["api", "get-examples", "-t", "xyz", "-o", str(path)]
269 )
270 sb.assert_result_ok(result)
272 # -- Read and verify the file.
273 text = sb.read_file(path)
274 data = json.loads(text)
275 assert data["timestamp"] == "xyz"
276 assert (
277 data["examples"]["alhambra-ii"]["blinky"]["description"]
278 == "Blinking led"
279 )
282def test_apio_api_scan_devices(apio_runner: ApioRunner):
283 """Test "apio api scan-devices" """
285 with apio_runner.in_sandbox() as sb:
287 # -- Execute "apio api scan-devices -t xyz". We run it in a
288 # -- subprocess such that it releases the libusb1 file it uses.
289 # -- This also means that it's not included in the pytest test
290 # -- coverage report.
291 result = sb.invoke_apio_cmd(
292 apio, ["api", "scan-devices", "-t", "xyz"], in_subprocess=True
293 )
294 sb.assert_result_ok(result)
296 assert "xyz" in result.output
297 assert "usb-devices" in result.output
298 assert "serial-devices" in result.output
300 # -- Execute "apio api get-boards -t xyz -s boards -o <dir>" (file)
301 path = sb.proj_dir / "apio.json"
303 result = sb.invoke_apio_cmd(
304 apio,
305 ["api", "scan-devices", "-t", "xyz", "-o", str(path)],
306 in_subprocess=True,
307 )
308 sb.assert_result_ok(result)
310 # -- Read and verify the output file. Since we don't know what
311 # -- devices the platform has, we just check for the section keys.
312 text = sb.read_file(path)
313 data = json.loads(text)
314 assert data["timestamp"] == "xyz"
315 assert "usb-devices" in data
316 assert "serial-devices" in data
319def test_apio_api_echo(apio_runner: ApioRunner):
320 """Test "apio api echo" """
322 with apio_runner.in_sandbox() as sb:
324 # -- Execute "apio api scan-devices -t xyz". We run it in a
325 # -- subprocess such that it releases the libusb1 file it uses.
326 # -- This also means that it's not included in the pytest test
327 # -- coverage report.
328 result = sb.invoke_apio_cmd(
329 apio,
330 ["api", "echo", "-t", "Hello world", "-s", "OK"],
331 in_subprocess=True,
332 )
333 sb.assert_result_ok(result)
335 assert "Hello world" in result.output