Coverage for tests / unit_tests / test_resources.py: 100%
56 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"""
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_platforms,
18 _validate_board_info,
19 validate_fpga_info,
20 _validate_programmer_info,
21 collect_project_resources,
22 validate_project_resources,
23)
26def lc_part_num(part_num: str) -> str:
27 """Convert an fpga part number to a lower-case id."""
28 return part_num.lower().replace("/", "-")
31def test_resources_references(apio_runner: ApioRunner):
32 """Tests the consistency of the board references to fpgas and
33 programmers."""
35 with apio_runner.in_sandbox():
37 # -- Create an apio context so we can access the resources.
38 apio_ctx = ApioContext(
39 project_policy=ProjectPolicy.NO_PROJECT,
40 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
41 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
42 )
44 unused_programmers = set(apio_ctx.programmers.keys())
46 for board_id, board_info in apio_ctx.boards.items():
47 # -- Prepare a context message for failing assertions.
48 board_msg = f"While testing board {board_id}"
50 # -- Assert that required fields exist.
51 assert "fpga-id" in board_info, board_msg
52 assert "programmer" in board_info, board_msg
53 assert "id" in board_info["programmer"], board_msg
55 # -- Check that the fpga exists.
56 board_fpga_id = board_info["fpga-id"]
57 assert apio_ctx.fpgas[board_fpga_id], board_msg
59 # -- Check that the programmer exists.
60 board_programmer_id = board_info["programmer"]["id"]
61 assert apio_ctx.programmers[board_programmer_id], board_msg
63 # -- Track unused programmers. Since a programmer may be used
64 # -- by more than one board, it may already be removed.
65 if board_programmer_id in unused_programmers:
66 unused_programmers.remove(board_programmer_id)
68 # -- We should end up with an empty set of unused programmers.
69 assert not unused_programmers, unused_programmers
72def test_resources_ids_and_order(apio_runner: ApioRunner):
73 """Tests the formats of boards, fpgas, and programmers names."""
75 # -- For boards we allow lower-case-0-9.
76 board_id_regex = re.compile(r"^[a-z][a-z0-9-]*$")
78 # -- For fpga ids we allow lower-case-0-9.
79 fpga_id_regex = re.compile(r"^[a-z][a-z0-9-/]*$")
81 # -- For programmer ids we allow lower-case-0-9.
82 programmer_id_regex = re.compile(r"^[a-z][a-z0-9-]*$")
84 with apio_runner.in_sandbox():
86 # -- Create an apio context so we can access the resources.
87 apio_ctx = ApioContext(
88 project_policy=ProjectPolicy.NO_PROJECT,
89 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
90 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
91 )
93 # -- Test the format of the board ids.
94 for board_id in apio_ctx.boards.keys():
95 assert board_id_regex.match(board_id), f"{board_id=}"
97 # -- Test the format of the fpgas ids and part numbers.
98 for fpga_id, fgpa_info in apio_ctx.fpgas.items():
99 assert fpga_id_regex.match(fpga_id), f"{fpga_id=}"
100 # Fpga id is either the fpga part num converted to lower-case
101 # or its the lower-case part num with a suffix that starts with
102 # '-'. E.g, for part num 'PART-NUM', the fpga id can be 'part-num'
103 # or 'part-num-somethings'
104 lc_part = lc_part_num(fgpa_info["part-num"])
105 assert fpga_id == lc_part or fpga_id.startswith(
106 lc_part + "-"
107 ), f"{fpga_id=}"
109 # -- Test the format of the programmers ids.
110 for programmer_id in apio_ctx.programmers.keys():
111 assert programmer_id_regex.match(
112 programmer_id
113 ), f"{programmer_id=}"
116def test_resources_are_valid(apio_runner: ApioRunner):
117 """Validate resources against a schema."""
118 with apio_runner.in_sandbox():
120 apio_ctx = ApioContext(
121 project_policy=ProjectPolicy.NO_PROJECT,
122 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
123 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
124 )
126 validate_config(apio_ctx.config)
127 validate_packages(apio_ctx.all_packages)
128 validate_platforms(apio_ctx.platforms)
130 for fpga_id, fpga_info in apio_ctx.fpgas.items():
131 validate_fpga_info(fpga_id, fpga_info)
133 for programmer_id, programmer_info in apio_ctx.programmers.items():
134 _validate_programmer_info(programmer_id, programmer_info)
136 for board_id, board_info in apio_ctx.boards.items():
137 _validate_board_info(board_id, board_info)
139 # -- Collect project resources for this board. This tests that
140 # -- the references are ok.
141 project_resources = collect_project_resources(
142 board_id, apio_ctx.boards, apio_ctx.fpgas, apio_ctx.programmers
143 )
145 # -- Validate the project resources.
146 validate_project_resources(project_resources)
149def test_fpga_definitions(apio_runner: ApioRunner):
150 """Tests the fields of the fpga definitions."""
152 with apio_runner.in_sandbox():
154 # -- Create an apio context so we can access the resources.
155 apio_ctx = ApioContext(
156 project_policy=ProjectPolicy.NO_PROJECT,
157 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
158 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
159 )
161 for fpga_id, fpga_info in apio_ctx.fpgas.items():
162 resource_util.validate_fpga_info(fpga_id, fpga_info)