Coverage for tsfpga/vivado/test/test_build_result_checker.py: 100%

93 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-21 23:39 +0000

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

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

3# 

4# This file is part of the tsfpga project, a project platform for modern FPGA development. 

5# https://tsfpga.com 

6# https://github.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8 

9import io 

10from unittest.mock import Mock, patch 

11 

12import pytest 

13 

14from tsfpga.vivado.build_result import VivadoBuildResult 

15from tsfpga.vivado.build_result_checker import ( 

16 BlockRams, 

17 DspBlocks, 

18 EqualTo, 

19 GreaterThan, 

20 LessThan, 

21 MaximumLogicLevel, 

22 Ramb, 

23 Ramb36, 

24 TotalLuts, 

25) 

26 

27 

28@patch("sys.stdout", new_callable=io.StringIO) 

29def test_size_checker_less_than_pass(mock_stdout): 

30 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

31 build_result.synthesis_size = {"Total LUTs": 5} 

32 

33 assert TotalLuts(LessThan(10)).check(build_result) 

34 assert mock_stdout.getvalue() == "Result check passed for Total LUTs: 5 (< 10)\n" 

35 

36 

37@patch("sys.stdout", new_callable=io.StringIO) 

38def test_size_checker_less_than_fail(mock_stdout): 

39 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

40 build_result.synthesis_size = {"Total LUTs": 5} 

41 

42 assert not TotalLuts(LessThan(5)).check(build_result) 

43 assert mock_stdout.getvalue() == "Result check failed for Total LUTs. Got 5, expected < 5.\n" 

44 

45 

46@patch("sys.stdout", new_callable=io.StringIO) 

47def test_size_checker_greater_than_pass(mock_stdout): 

48 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

49 build_result.synthesis_size = {"Total LUTs": 5} 

50 

51 assert TotalLuts(GreaterThan(2)).check(build_result) 

52 assert mock_stdout.getvalue() == "Result check passed for Total LUTs: 5 (> 2)\n" 

53 

54 

55@patch("sys.stdout", new_callable=io.StringIO) 

56def test_size_checker_greater_than_fail(mock_stdout): 

57 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

58 build_result.synthesis_size = {"Total LUTs": 5} 

59 

60 assert not TotalLuts(GreaterThan(5)).check(build_result) 

61 assert mock_stdout.getvalue() == "Result check failed for Total LUTs. Got 5, expected > 5.\n" 

62 

63 

64@patch("sys.stdout", new_callable=io.StringIO) 

65def test_size_checker_equal_to_pass(mock_stdout): 

66 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

67 build_result.synthesis_size = {"RAMB36": 0, "Total LUTs": 5} 

68 

69 assert Ramb36(EqualTo(0)).check(build_result) 

70 assert TotalLuts(EqualTo(5)).check(build_result) 

71 

72 assert mock_stdout.getvalue() == ( 

73 "Result check passed for RAMB36: 0 (0)\nResult check passed for Total LUTs: 5 (5)\n" 

74 ) 

75 

76 

77@patch("sys.stdout", new_callable=io.StringIO) 

78def test_size_checker_equal_to_fail(mock_stdout): 

79 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

80 build_result.synthesis_size = {"Total LUTs": 5} 

81 

82 assert not TotalLuts(EqualTo(50)).check(build_result) 

83 assert mock_stdout.getvalue() == "Result check failed for Total LUTs. Got 5, expected 50.\n" 

84 

85 

86def test_size_checker_block_rams_is_architecture_agnostic(): 

87 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

88 

89 build_result.synthesis_size = {"Block RAMs": 3} 

90 assert BlockRams(EqualTo(3)).check(build_result) 

91 assert not BlockRams(EqualTo(1)).check(build_result) 

92 

93 

94def test_size_checker_dsp_blocks_has_two_names(): 

95 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

96 

97 build_result.synthesis_size = {"DSP Blocks": 5} 

98 assert DspBlocks(EqualTo(5)).check(build_result) 

99 assert not DspBlocks(EqualTo(2)).check(build_result) 

100 

101 build_result.synthesis_size = {"DSP48 Blocks": 7} 

102 assert DspBlocks(EqualTo(7)).check(build_result) 

103 assert not DspBlocks(EqualTo(2)).check(build_result) 

104 

105 

106def test_size_checker_aggregated_ramb(): 

107 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

108 

109 build_result.synthesis_size = {"RAMB18": 5, "RAMB36": 20} 

110 assert Ramb(EqualTo(22.5)).check(build_result) 

111 assert not Ramb(EqualTo(22)).check(build_result) 

112 

113 build_result.synthesis_size = {"RAMB18": 5, "RAMB36": 0} 

114 assert Ramb(EqualTo(2.5)).check(build_result) 

115 

116 build_result.synthesis_size = {"RAMB18": 0, "RAMB36": 20} 

117 assert Ramb(EqualTo(20)).check(build_result) 

118 

119 

120def test_size_checker_raises_exception_if_synthesis_size_is_not_set(): 

121 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

122 build_result.synthesis_size = None 

123 

124 with pytest.raises(ValueError) as exception_info: 

125 assert Ramb36(EqualTo(0)).check(build_result) 

126 assert str(exception_info.value) == "Should only call after successful synthesis" 

127 

128 

129def test_size_checker_raises_exception_if_synthesis_size_does_not_have_requested_resource(): 

130 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

131 build_result.synthesis_size = {"Total LUTs": 5} 

132 

133 with pytest.raises(ValueError) as exception_info: 

134 assert Ramb36(EqualTo(0)).check(build_result) 

135 assert ( 

136 str(exception_info.value) 

137 == 'Synthesis result size does not contain the requested resource: "RAMB36"' 

138 ) 

139 

140 

141@patch("sys.stdout", new_callable=io.StringIO) 

142def test_logic_level_checker_equal_to_pass(mock_stdout): 

143 build_result = Mock(spec=VivadoBuildResult) 

144 build_result.maximum_logic_level = 5 

145 

146 assert MaximumLogicLevel(EqualTo(5)).check(build_result) 

147 assert mock_stdout.getvalue() == "Result check passed for maximum logic level: 5 (5)\n" 

148 

149 

150@patch("sys.stdout", new_callable=io.StringIO) 

151def test_logic_level_checker_less_than_fail(mock_stdout): 

152 build_result = Mock(spec=VivadoBuildResult) 

153 build_result.maximum_logic_level = 11 

154 assert not MaximumLogicLevel(LessThan(7)).check(build_result) 

155 assert ( 

156 mock_stdout.getvalue() 

157 == "Result check failed for maximum logic level. Got 11, expected < 7.\n" 

158 ) 

159 

160 

161def test_logic_level_checker_raises_exception_if_logic_level_is_not_set(): 

162 build_result = VivadoBuildResult(name="", synthesis_run_name="") 

163 

164 with pytest.raises(ValueError) as exception_info: 

165 MaximumLogicLevel(LessThan(7)).check(build_result) 

166 assert str(exception_info.value) == "Should only call after successful synthesis"