Coverage for hdl_registers/field/test/test_integer.py: 100%

136 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-07 20:51 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the hdl-registers project, an HDL register generator fast enough to run 

5# in real time. 

6# https://hdl-registers.com 

7# https://github.com/hdl-registers/hdl-registers 

8# -------------------------------------------------------------------------------------------------- 

9 

10# Standard libraries 

11from copy import copy 

12 

13# Third party libraries 

14import pytest 

15 

16# First party libraries 

17from hdl_registers.field.integer import Integer 

18 

19TEST_FIELD = Integer( 

20 name="apa", 

21 base_index=3, 

22 description="hest", 

23 min_value=120, 

24 max_value=456, 

25 default_value=127, 

26) 

27 

28 

29def test_fields(): 

30 assert TEST_FIELD.name == "apa" 

31 assert TEST_FIELD.base_index == 3 

32 assert TEST_FIELD.description == "hest" 

33 assert TEST_FIELD.min_value == 120 

34 assert TEST_FIELD.max_value == 456 

35 assert TEST_FIELD.default_value == 127 

36 

37 

38def test_repr_is_an_actual_representation(): 

39 # Check that repr is an actual representation, not just "X object at 0xABCDEF" 

40 assert "apa" in repr(TEST_FIELD) 

41 

42 

43def test_repr_is_same_after_copy(): 

44 field = copy(TEST_FIELD) 

45 

46 assert repr(field) == repr(TEST_FIELD) 

47 

48 

49def test_repr_should_change_when_name_is_changed(): 

50 field = copy(TEST_FIELD) 

51 field.name = "zebra" 

52 

53 assert repr(field) != repr(TEST_FIELD) 

54 

55 

56def test_repr_should_change_when_default_value_is_changed(): 

57 field = copy(TEST_FIELD) 

58 field.default_value = 133 

59 

60 assert repr(field) != repr(TEST_FIELD) 

61 

62 

63def test_repr_when_static_members_have_different_value(): 

64 original_field = Integer( 

65 name="apa", 

66 base_index=0, 

67 description="", 

68 min_value=10, 

69 max_value=10, 

70 default_value=10, 

71 ) 

72 

73 # Different base_index 

74 assert repr( 

75 Integer( 

76 name="apa", 

77 base_index=25, 

78 description="", 

79 min_value=10, 

80 max_value=10, 

81 default_value=10, 

82 ) 

83 ) != repr(original_field) 

84 

85 # Different description 

86 assert repr( 

87 Integer( 

88 name="apa", 

89 base_index=0, 

90 description="blah", 

91 min_value=10, 

92 max_value=10, 

93 default_value=10, 

94 ) 

95 ) != repr(original_field) 

96 

97 # Different min_value 

98 assert repr( 

99 Integer( 

100 name="apa", 

101 base_index=0, 

102 description="", 

103 min_value=5, 

104 max_value=10, 

105 default_value=10, 

106 ) 

107 ) != repr(original_field) 

108 

109 # Different max_value 

110 assert repr( 

111 Integer( 

112 name="apa", 

113 base_index=0, 

114 description="", 

115 min_value=10, 

116 max_value=15, 

117 default_value=10, 

118 ) 

119 ) != repr(original_field) 

120 

121 

122def test_is_signed(): 

123 def get_is_signed(min_value, max_value): 

124 return Integer( 

125 name="", 

126 base_index=0, 

127 description="", 

128 min_value=min_value, 

129 max_value=max_value, 

130 default_value=min_value, 

131 ).is_signed 

132 

133 assert get_is_signed(min_value=-10, max_value=10) 

134 assert get_is_signed(min_value=-10, max_value=-5) 

135 assert not get_is_signed(min_value=0, max_value=10) 

136 assert not get_is_signed(min_value=5, max_value=10) 

137 

138 

139def test_non_ascending_range_should_raise_exception(): 

140 with pytest.raises(ValueError) as exception_info: 

141 Integer( 

142 name="apa", base_index=0, description="", min_value=10, max_value=0, default_value=0 

143 ) 

144 

145 assert ( 

146 str(exception_info.value) 

147 == 'Integer field "apa" should have ascending range. Got: [10, 0].' 

148 ) 

149 

150 

151def test_non_integer_range_should_raise_exception(): 

152 with pytest.raises(ValueError) as exception_info: 

153 Integer( 

154 name="apa", 

155 base_index=0, 

156 description="", 

157 min_value="5", 

158 max_value=10, 

159 default_value=11, 

160 ) 

161 assert ( 

162 str(exception_info.value) 

163 == 'Integer field "apa" should have integer value for "min_value". Got: "5".' 

164 ) 

165 

166 with pytest.raises(ValueError) as exception_info: 

167 Integer( 

168 name="apa", 

169 base_index=0, 

170 description="", 

171 min_value=5, 

172 max_value="X", 

173 default_value=11, 

174 ) 

175 assert ( 

176 str(exception_info.value) 

177 == 'Integer field "apa" should have integer value for "max_value". Got: "X".' 

178 ) 

179 

180 

181def test_get_value_unsigned(): 

182 integer = Integer( 

183 name="", base_index=2, min_value=0, max_value=127, description="", default_value=0 

184 ) 

185 assert integer.width == 7 

186 

187 register_value = int("0101010_11", base=2) 

188 assert integer.get_value(register_value) == 42 

189 

190 register_value = int("1010101_00", base=2) 

191 assert integer.get_value(register_value) == 85 

192 

193 

194def test_get_value_signed(): 

195 integer = Integer( 

196 name="", base_index=3, min_value=-128, max_value=127, description="", default_value=0 

197 ) 

198 assert integer.width == 8 

199 

200 register_value = int("10101010_111", base=2) 

201 assert integer.get_value(register_value) == -86 

202 

203 register_value = int("01010101_000", base=2) 

204 assert integer.get_value(register_value) == 85 

205 

206 

207def test_get_value_should_raise_exception_if_value_out_of_range(): 

208 integer = Integer( 

209 name="apa", base_index=0, min_value=0, max_value=4, description="", default_value=0 

210 ) 

211 assert integer.width == 3 

212 

213 with pytest.raises(ValueError) as exception_info: 

214 integer.get_value(7) 

215 assert ( 

216 str(exception_info.value) 

217 == 'Register field value "7" not inside "apa" field\'s legal range: (0, 4).' 

218 ) 

219 

220 

221def test_set_value_unsigned(): 

222 integer = Integer( 

223 name="", base_index=5, min_value=0, max_value=7, description="", default_value=0 

224 ) 

225 assert integer.width == 3 

226 

227 assert integer.set_value(5) == int("101_00000", base=2) 

228 assert integer.set_value(2) == int("010_00000", base=2) 

229 

230 

231def test_set_value_signed(): 

232 integer = Integer( 

233 name="", base_index=5, min_value=-8, max_value=7, description="", default_value=0 

234 ) 

235 assert integer.width == 4 

236 

237 assert integer.set_value(5) == int("0101_00000", base=2) 

238 assert integer.set_value(-6) == int("1010_00000", base=2) 

239 

240 

241def test_set_value_should_raise_exception_if_value_out_of_range(): 

242 integer = Integer( 

243 name="apa", base_index=5, min_value=-1, max_value=7, description="", default_value=0 

244 ) 

245 

246 with pytest.raises(ValueError) as exception_info: 

247 integer.set_value(-8) 

248 assert str(exception_info.value) == 'Value "-8" not inside "apa" field\'s legal range: (-1, 7).' 

249 

250 

251def test_default_value_uint(): 

252 def _get_default_value_uint(min_value, max_value, default_value): 

253 return Integer( 

254 name="", 

255 base_index=0, 

256 description="", 

257 min_value=min_value, 

258 max_value=max_value, 

259 default_value=default_value, 

260 ).default_value_uint 

261 

262 assert _get_default_value_uint(min_value=5, max_value=10, default_value=7) == 7 

263 assert _get_default_value_uint(min_value=-10, max_value=10, default_value=3) == 3 

264 

265 # Negative values, converted to positive and sign extended to the width of the field. 

266 assert _get_default_value_uint(min_value=-10, max_value=10, default_value=-9) == 0b10111 

267 assert _get_default_value_uint(min_value=-10, max_value=10, default_value=-6) == 0b11010 

268 

269 

270def test_default_value_of_bad_type_should_raise_exception(): 

271 with pytest.raises(ValueError) as exception_info: 

272 Integer( 

273 name="apa", 

274 base_index=0, 

275 description="", 

276 min_value=5, 

277 max_value=10, 

278 default_value="7", 

279 ) 

280 assert ( 

281 str(exception_info.value) 

282 == 'Integer field "apa" should have integer value for "default_value". Got: "7".' 

283 ) 

284 

285 field = Integer( 

286 name="apa", 

287 base_index=0, 

288 description="", 

289 min_value=5, 

290 max_value=10, 

291 default_value=5, 

292 ) 

293 

294 with pytest.raises(ValueError) as exception_info: 

295 field.default_value = "8" 

296 assert ( 

297 str(exception_info.value) 

298 == 'Integer field "apa" should have integer value for "default_value". Got: "8".' 

299 ) 

300 

301 

302def test_default_value_out_of_range_should_raise_exception(): 

303 with pytest.raises(ValueError) as exception_info: 

304 Integer( 

305 name="apa", 

306 base_index=0, 

307 description="", 

308 min_value=5, 

309 max_value=10, 

310 default_value=11, 

311 ) 

312 assert ( 

313 str(exception_info.value) 

314 == 'Integer field "apa" should have "default_value" within range [5, 10]. Got: "11".' 

315 ) 

316 

317 field = Integer( 

318 name="apa", 

319 base_index=0, 

320 description="", 

321 min_value=5, 

322 max_value=10, 

323 default_value=5, 

324 ) 

325 

326 with pytest.raises(ValueError) as exception_info: 

327 field.default_value = 120 

328 assert ( 

329 str(exception_info.value) 

330 == 'Integer field "apa" should have "default_value" within range [5, 10]. Got: "120".' 

331 ) 

332 

333 

334def _get_field_width(min_value, max_value): 

335 return Integer( 

336 name="", 

337 base_index=0, 

338 description="", 

339 min_value=min_value, 

340 max_value=max_value, 

341 default_value=min_value, 

342 ).width 

343 

344 

345def test_unsigned_width(): 

346 assert _get_field_width(min_value=0, max_value=127) == 7 

347 assert _get_field_width(min_value=0, max_value=128) == 8 

348 assert _get_field_width(min_value=0, max_value=255) == 8 

349 assert _get_field_width(min_value=0, max_value=256) == 9 

350 

351 # The lower bound of the range does not affect the width 

352 # (but it will add checkers in our generated code). 

353 assert _get_field_width(min_value=255, max_value=255) == 8 

354 

355 

356def test_signed_width(): 

357 # Positive range has greater demand than negative 

358 assert _get_field_width(min_value=-4, max_value=16) == 5 + 1 

359 assert _get_field_width(min_value=-4, max_value=4) == 3 + 1 

360 

361 # Negative range has greater demand than positive 

362 assert _get_field_width(min_value=-7, max_value=2) == 4 

363 assert _get_field_width(min_value=-8, max_value=2) == 4 

364 assert _get_field_width(min_value=-9, max_value=2) == 5 

365 

366 assert _get_field_width(min_value=-15, max_value=7) == 5 

367 assert _get_field_width(min_value=-16, max_value=7) == 5 

368 assert _get_field_width(min_value=-17, max_value=7) == 6 

369 

370 # The upper bound of the range here does not affect the width 

371 # (but it will add checkers in our generated code). 

372 assert _get_field_width(min_value=-8, max_value=-3) == 4 

373 assert _get_field_width(min_value=-16, max_value=-4) == 5 

374 

375 

376def test_width_out_of_range_should_raise_exception(): 

377 def _test_width_out_of_range(min_value, max_value): 

378 with pytest.raises(ValueError) as exception_info: 

379 _get_field_width(min_value=min_value, max_value=max_value) 

380 assert ( 

381 str(exception_info.value) 

382 == f"Supplied integer range [{min_value}, {max_value}] does not fit in a register." 

383 ) 

384 

385 # Unsigned. Just within range, should not raise exception. 

386 _get_field_width(min_value=128, max_value=2**32 - 1) 

387 # Just outside of range. 

388 _test_width_out_of_range(min_value=128, max_value=2**32) 

389 

390 # Signed, limited by negative range. Just within range, should not raise exception. 

391 _get_field_width(min_value=-(2**31), max_value=128) 

392 # Just outside of range. 

393 _test_width_out_of_range(min_value=-(2**31) - 1, max_value=128) 

394 

395 # Signed, limited by positive range. Just within range, should not raise exception. 

396 _get_field_width(min_value=-128, max_value=2**31 - 1) 

397 # Just outside of range. 

398 _test_width_out_of_range(min_value=-128, max_value=2**31)