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
« 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# --------------------------------------------------------------------------------------------------
9import io
10from unittest.mock import Mock, patch
12import pytest
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)
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}
33 assert TotalLuts(LessThan(10)).check(build_result)
34 assert mock_stdout.getvalue() == "Result check passed for Total LUTs: 5 (< 10)\n"
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}
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"
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}
51 assert TotalLuts(GreaterThan(2)).check(build_result)
52 assert mock_stdout.getvalue() == "Result check passed for Total LUTs: 5 (> 2)\n"
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}
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"
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}
69 assert Ramb36(EqualTo(0)).check(build_result)
70 assert TotalLuts(EqualTo(5)).check(build_result)
72 assert mock_stdout.getvalue() == (
73 "Result check passed for RAMB36: 0 (0)\nResult check passed for Total LUTs: 5 (5)\n"
74 )
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}
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"
86def test_size_checker_block_rams_is_architecture_agnostic():
87 build_result = VivadoBuildResult(name="", synthesis_run_name="")
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)
94def test_size_checker_dsp_blocks_has_two_names():
95 build_result = VivadoBuildResult(name="", synthesis_run_name="")
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)
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)
106def test_size_checker_aggregated_ramb():
107 build_result = VivadoBuildResult(name="", synthesis_run_name="")
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)
113 build_result.synthesis_size = {"RAMB18": 5, "RAMB36": 0}
114 assert Ramb(EqualTo(2.5)).check(build_result)
116 build_result.synthesis_size = {"RAMB18": 0, "RAMB36": 20}
117 assert Ramb(EqualTo(20)).check(build_result)
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
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"
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}
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 )
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
146 assert MaximumLogicLevel(EqualTo(5)).check(build_result)
147 assert mock_stdout.getvalue() == "Result check passed for maximum logic level: 5 (5)\n"
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 )
161def test_logic_level_checker_raises_exception_if_logic_level_is_not_set():
162 build_result = VivadoBuildResult(name="", synthesis_run_name="")
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"