Coverage for tsfpga/vivado/test/test_build_result_checker.py: 100%
88 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-21 20:51 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-21 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# --------------------------------------------------------------------------------------------------
9import io
10from unittest.mock import Mock, patch
12import pytest
14from tsfpga.vivado.build_result import BuildResult
15from tsfpga.vivado.build_result_checker import (
16 DspBlocks,
17 EqualTo,
18 GreaterThan,
19 LessThan,
20 MaximumLogicLevel,
21 Ramb,
22 Ramb36,
23 TotalLuts,
24)
27@patch("sys.stdout", new_callable=io.StringIO)
28def test_size_checker_less_than_pass(mock_stdout):
29 build_result = BuildResult(name="")
30 build_result.synthesis_size = {"Total LUTs": 5}
32 assert TotalLuts(LessThan(10)).check(build_result)
33 assert mock_stdout.getvalue() == "Result check passed for Total LUTs: 5 (< 10)\n"
36@patch("sys.stdout", new_callable=io.StringIO)
37def test_size_checker_less_than_fail(mock_stdout):
38 build_result = BuildResult(name="")
39 build_result.synthesis_size = {"Total LUTs": 5}
41 assert not TotalLuts(LessThan(5)).check(build_result)
42 assert mock_stdout.getvalue() == "Result check failed for Total LUTs. Got 5, expected < 5.\n"
45@patch("sys.stdout", new_callable=io.StringIO)
46def test_size_checker_greater_than_pass(mock_stdout):
47 build_result = BuildResult(name="")
48 build_result.synthesis_size = {"Total LUTs": 5}
50 assert TotalLuts(GreaterThan(2)).check(build_result)
51 assert mock_stdout.getvalue() == "Result check passed for Total LUTs: 5 (> 2)\n"
54@patch("sys.stdout", new_callable=io.StringIO)
55def test_size_checker_greater_than_fail(mock_stdout):
56 build_result = BuildResult(name="")
57 build_result.synthesis_size = {"Total LUTs": 5}
59 assert not TotalLuts(GreaterThan(5)).check(build_result)
60 assert mock_stdout.getvalue() == "Result check failed for Total LUTs. Got 5, expected > 5.\n"
63@patch("sys.stdout", new_callable=io.StringIO)
64def test_size_checker_equal_to_pass(mock_stdout):
65 build_result = BuildResult(name="")
66 build_result.synthesis_size = {"RAMB36": 0, "Total LUTs": 5}
68 assert Ramb36(EqualTo(0)).check(build_result)
69 assert TotalLuts(EqualTo(5)).check(build_result)
71 assert mock_stdout.getvalue() == (
72 "Result check passed for RAMB36: 0 (0)\nResult check passed for Total LUTs: 5 (5)\n"
73 )
76@patch("sys.stdout", new_callable=io.StringIO)
77def test_size_checker_equal_to_fail(mock_stdout):
78 build_result = BuildResult(name="")
79 build_result.synthesis_size = {"Total LUTs": 5}
81 assert not TotalLuts(EqualTo(50)).check(build_result)
82 assert mock_stdout.getvalue() == "Result check failed for Total LUTs. Got 5, expected 50.\n"
85def test_size_checker_dsp_blocks_has_two_names():
86 build_result = BuildResult(name="")
88 build_result.synthesis_size = {"DSP Blocks": 5}
89 assert DspBlocks(EqualTo(5)).check(build_result)
90 assert not DspBlocks(EqualTo(2)).check(build_result)
92 build_result.synthesis_size = {"DSP48 Blocks": 7}
93 assert DspBlocks(EqualTo(7)).check(build_result)
94 assert not DspBlocks(EqualTo(2)).check(build_result)
97def test_size_checker_aggregated_ramb():
98 build_result = BuildResult(name="")
100 build_result.synthesis_size = {"RAMB18": 5, "RAMB36": 20}
101 assert Ramb(EqualTo(22.5)).check(build_result)
102 assert not Ramb(EqualTo(22)).check(build_result)
104 build_result.synthesis_size = {"RAMB18": 5, "RAMB36": 0}
105 assert Ramb(EqualTo(2.5)).check(build_result)
107 build_result.synthesis_size = {"RAMB18": 0, "RAMB36": 20}
108 assert Ramb(EqualTo(20)).check(build_result)
111def test_size_checker_raises_exception_if_synthesis_size_is_not_set():
112 build_result = BuildResult(name="")
113 build_result.synthesis_size = None
115 with pytest.raises(ValueError) as exception_info:
116 assert Ramb36(EqualTo(0)).check(build_result)
117 assert str(exception_info.value) == "Should only call after successful synthesis"
120def test_size_checker_raises_exception_if_synthesis_size_does_not_have_requested_resource():
121 build_result = BuildResult(name="")
122 build_result.synthesis_size = {"Total LUTs": 5}
124 with pytest.raises(ValueError) as exception_info:
125 assert Ramb36(EqualTo(0)).check(build_result)
126 assert (
127 str(exception_info.value)
128 == 'Synthesis result size does not contain the requested resource: "RAMB36"'
129 )
132@patch("sys.stdout", new_callable=io.StringIO)
133def test_logic_level_checker_equal_to_pass(mock_stdout):
134 build_result = Mock(spec=BuildResult)
135 build_result.maximum_logic_level = 5
137 assert MaximumLogicLevel(EqualTo(5)).check(build_result)
138 assert mock_stdout.getvalue() == "Result check passed for maximum logic level: 5 (5)\n"
141@patch("sys.stdout", new_callable=io.StringIO)
142def test_logic_level_checker_less_than_fail(mock_stdout):
143 build_result = Mock(spec=BuildResult)
144 build_result.maximum_logic_level = 11
145 assert not MaximumLogicLevel(LessThan(7)).check(build_result)
146 assert (
147 mock_stdout.getvalue()
148 == "Result check failed for maximum logic level. Got 11, expected < 7.\n"
149 )
152def test_logic_level_checker_raises_exception_if_logic_level_is_not_set():
153 build_result = BuildResult(name="")
155 with pytest.raises(ValueError) as exception_info:
156 MaximumLogicLevel(LessThan(7)).check(build_result)
157 assert str(exception_info.value) == "Should only call after successful synthesis"