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

76 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-06 20:51 +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 

9# Standard libraries 

10import io 

11from unittest.mock import Mock, patch 

12 

13# Third party libraries 

14import pytest 

15 

16# First party libraries 

17from tsfpga.vivado.build_result import BuildResult 

18from tsfpga.vivado.build_result_checker import ( 

19 DspBlocks, 

20 EqualTo, 

21 LessThan, 

22 MaximumLogicLevel, 

23 Ramb, 

24 Ramb36, 

25 TotalLuts, 

26) 

27 

28 

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

30def test_size_checker_less_than_pass(mock_stdout): 

31 build_result = BuildResult(name="") 

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

33 

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

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

36 

37 

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

39def test_size_checker_less_than_fail(mock_stdout): 

40 build_result = BuildResult(name="") 

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

42 

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

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

45 

46 

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

48def test_size_checker_equal_to_pass(mock_stdout): 

49 build_result = BuildResult(name="") 

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

51 

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

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

54 

55 assert mock_stdout.getvalue() == ( 

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

57 ) 

58 

59 

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

61def test_size_checker_equal_to_fail(mock_stdout): 

62 build_result = BuildResult(name="") 

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

64 

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

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

67 

68 

69def test_size_checker_dsp_blocks_has_two_names(): 

70 build_result = BuildResult(name="") 

71 

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

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

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

75 

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

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

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

79 

80 

81def test_size_checker_aggregated_ramb(): 

82 build_result = BuildResult(name="") 

83 

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

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

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

87 

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

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

90 

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

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

93 

94 

95def test_size_checker_raises_exception_if_synthesis_size_is_not_set(): 

96 build_result = BuildResult(name="") 

97 build_result.synthesis_size = None 

98 

99 with pytest.raises(ValueError) as exception_info: 

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

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

102 

103 

104def test_size_checker_raises_exception_if_synthesis_size_does_not_have_requested_resource(): 

105 build_result = BuildResult(name="") 

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

107 

108 with pytest.raises(ValueError) as exception_info: 

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

110 assert ( 

111 str(exception_info.value) 

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

113 ) 

114 

115 

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

117def test_logic_level_checker_equal_to_pass(mock_stdout): 

118 build_result = Mock(spec=BuildResult) 

119 build_result.maximum_logic_level = 5 

120 

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

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

123 

124 

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

126def test_logic_level_checker_less_than_fail(mock_stdout): 

127 build_result = Mock(spec=BuildResult) 

128 build_result.maximum_logic_level = 11 

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

130 assert ( 

131 mock_stdout.getvalue() 

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

133 ) 

134 

135 

136def test_logic_level_checker_raises_exception_if_logic_level_is_not_set(): 

137 build_result = BuildResult(name="") 

138 

139 with pytest.raises(ValueError) as exception_info: 

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

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