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

1""" 

2Tests of apio_context.py 

3""" 

4 

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) 

24 

25 

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("/", "-") 

29 

30 

31def test_resources_references(apio_runner: ApioRunner): 

32 """Tests the consistency of the board references to fpgas and 

33 programmers.""" 

34 

35 with apio_runner.in_sandbox(): 

36 

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 ) 

43 

44 unused_programmers = set(apio_ctx.programmers.keys()) 

45 

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}" 

49 

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 

54 

55 # -- Check that the fpga exists. 

56 board_fpga_id = board_info["fpga-id"] 

57 assert apio_ctx.fpgas[board_fpga_id], board_msg 

58 

59 # -- Check that the programmer exists. 

60 board_programmer_id = board_info["programmer"]["id"] 

61 assert apio_ctx.programmers[board_programmer_id], board_msg 

62 

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) 

67 

68 # -- We should end up with an empty set of unused programmers. 

69 assert not unused_programmers, unused_programmers 

70 

71 

72def test_resources_ids_and_order(apio_runner: ApioRunner): 

73 """Tests the formats of boards, fpgas, and programmers names.""" 

74 

75 # -- For boards we allow lower-case-0-9. 

76 board_id_regex = re.compile(r"^[a-z][a-z0-9-]*$") 

77 

78 # -- For fpga ids we allow lower-case-0-9. 

79 fpga_id_regex = re.compile(r"^[a-z][a-z0-9-/]*$") 

80 

81 # -- For programmer ids we allow lower-case-0-9. 

82 programmer_id_regex = re.compile(r"^[a-z][a-z0-9-]*$") 

83 

84 with apio_runner.in_sandbox(): 

85 

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 ) 

92 

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=}" 

96 

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=}" 

108 

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=}" 

114 

115 

116def test_resources_are_valid(apio_runner: ApioRunner): 

117 """Validate resources against a schema.""" 

118 with apio_runner.in_sandbox(): 

119 

120 apio_ctx = ApioContext( 

121 project_policy=ProjectPolicy.NO_PROJECT, 

122 remote_config_policy=RemoteConfigPolicy.CACHED_OK, 

123 packages_policy=PackagesPolicy.ENSURE_PACKAGES, 

124 ) 

125 

126 validate_config(apio_ctx.config) 

127 validate_packages(apio_ctx.all_packages) 

128 validate_platforms(apio_ctx.platforms) 

129 

130 for fpga_id, fpga_info in apio_ctx.fpgas.items(): 

131 validate_fpga_info(fpga_id, fpga_info) 

132 

133 for programmer_id, programmer_info in apio_ctx.programmers.items(): 

134 _validate_programmer_info(programmer_id, programmer_info) 

135 

136 for board_id, board_info in apio_ctx.boards.items(): 

137 _validate_board_info(board_id, board_info) 

138 

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 ) 

144 

145 # -- Validate the project resources. 

146 validate_project_resources(project_resources) 

147 

148 

149def test_fpga_definitions(apio_runner: ApioRunner): 

150 """Tests the fields of the fpga definitions.""" 

151 

152 with apio_runner.in_sandbox(): 

153 

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 ) 

160 

161 for fpga_id, fpga_info in apio_ctx.fpgas.items(): 

162 resource_util.validate_fpga_info(fpga_id, fpga_info)