Coverage for tests/unit_tests/test_resources.py: 100%
55 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"""
2Tests of apio_context.py
3"""
5import re
6from tests.conftest import ApioRunner
7from apio.utils import resource_util
8from apio.apio_context import (
9 ApioContext,
10 PackagesPolicy,
11 ProjectPolicy,
12 RemoteConfigPolicy,
13)
14from apio.utils.resource_util import (
15 validate_config,
16 validate_packages,
17 _validate_board_info,
18 validate_fpga_info,
19 _validate_programmer_info,
20 collect_project_resources,
21 validate_project_resources,
22)
25def lc_part_num(part_num: str) -> str:
26 """Convert an fpga part number to a lower-case id."""
27 return part_num.lower().replace("/", "-")
30def test_resources_references(apio_runner: ApioRunner):
31 """Tests the consistency of the board references to fpgas and
32 programmers."""
34 with apio_runner.in_sandbox():
36 # -- Create an apio context so we can access the resources.
37 apio_ctx = ApioContext(
38 project_policy=ProjectPolicy.NO_PROJECT,
39 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
40 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
41 )
43 unused_programmers = set(apio_ctx.programmers.keys())
45 for board_id, board_info in apio_ctx.boards.items():
46 # -- Prepare a context message for failing assertions.
47 board_msg = f"While testing board {board_id}"
49 # -- Assert that required fields exist.
50 assert "fpga-id" in board_info, board_msg
51 assert "programmer" in board_info, board_msg
52 assert "id" in board_info["programmer"], board_msg
54 # -- Check that the fpga exists.
55 board_fpga_id = board_info["fpga-id"]
56 assert apio_ctx.fpgas[board_fpga_id], board_msg
58 # -- Check that the programmer exists.
59 board_programmer_id = board_info["programmer"]["id"]
60 assert apio_ctx.programmers[board_programmer_id], board_msg
62 # -- Track unused programmers. Since a programmer may be used
63 # -- by more than one board, it may already be removed.
64 if board_programmer_id in unused_programmers:
65 unused_programmers.remove(board_programmer_id)
67 # -- We should end up with an empty set of unused programmers.
68 assert not unused_programmers, unused_programmers
71def test_resources_ids_and_order(apio_runner: ApioRunner):
72 """Tests the formats of boards, fpgas, and programmers names."""
74 # -- For boards we allow lower-case-0-9.
75 board_id_regex = re.compile(r"^[a-z][a-z0-9-]*$")
77 # -- For fpga ids we allow lower-case-0-9.
78 fpga_id_regex = re.compile(r"^[a-z][a-z0-9-/]*$")
80 # -- For programmer ids we allow lower-case-0-9.
81 programmer_id_regex = re.compile(r"^[a-z][a-z0-9-]*$")
83 with apio_runner.in_sandbox():
85 # -- Create an apio context so we can access the resources.
86 apio_ctx = ApioContext(
87 project_policy=ProjectPolicy.NO_PROJECT,
88 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
89 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
90 )
92 # -- Test the format of the board ids.
93 for board_id in apio_ctx.boards.keys():
94 assert board_id_regex.match(board_id), f"{board_id=}"
96 # -- Test the format of the fpgas ids and part numbers.
97 for fpga_id, fgpa_info in apio_ctx.fpgas.items():
98 assert fpga_id_regex.match(fpga_id), f"{fpga_id=}"
99 # Fpga id is either the fpga part num converted to lower-case
100 # or its the lower-case part num with a suffix that starts with
101 # '-'. E.g, for part num 'PART-NUM', the fpga id can be 'part-num'
102 # or 'part-num-somethings'
103 lc_part = lc_part_num(fgpa_info["part-num"])
104 assert fpga_id == lc_part or fpga_id.startswith(
105 lc_part + "-"
106 ), f"{fpga_id=}"
108 # -- Test the format of the programmers ids.
109 for programmer_id in apio_ctx.programmers.keys():
110 assert programmer_id_regex.match(
111 programmer_id
112 ), f"{programmer_id=}"
115def test_resources_are_valid(apio_runner: ApioRunner):
116 """Validate resources against a schema."""
117 with apio_runner.in_sandbox():
119 apio_ctx = ApioContext(
120 project_policy=ProjectPolicy.NO_PROJECT,
121 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
122 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
123 )
125 validate_config(apio_ctx.config)
126 validate_packages(apio_ctx.all_packages)
128 for fpga_id, fpga_info in apio_ctx.fpgas.items():
129 validate_fpga_info(fpga_id, fpga_info)
131 for programmer_id, programmer_info in apio_ctx.programmers.items():
132 _validate_programmer_info(programmer_id, programmer_info)
134 for board_id, board_info in apio_ctx.boards.items():
135 _validate_board_info(board_id, board_info)
137 # -- Collect project resources for this board. This tests that
138 # -- the references are ok.
139 project_resources = collect_project_resources(
140 board_id, apio_ctx.boards, apio_ctx.fpgas, apio_ctx.programmers
141 )
143 # -- Validate the project resources.
144 validate_project_resources(project_resources)
147def test_fpga_definitions(apio_runner: ApioRunner):
148 """Tests the fields of the fpga definitions."""
150 with apio_runner.in_sandbox():
152 # -- Create an apio context so we can access the resources.
153 apio_ctx = ApioContext(
154 project_policy=ProjectPolicy.NO_PROJECT,
155 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
156 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
157 )
159 for fpga_id, fpga_info in apio_ctx.fpgas.items():
160 resource_util.validate_fpga_info(fpga_id, fpga_info)