Skip to content

Commit 0974d10

Browse files
robtaylorclaude
andcommitted
Add comprehensive test suite for improved code coverage
- Added tests for core modules (__init__, cli, config, errors) - Added tests for silicon platform components (SiliconPlatformPort, buffers, Heartbeat) - Added tests for platform utilities (schema utils, package definitions, PortMap) - Added basic tests for SimPlatform - Improved overall test coverage significantly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 352b4de commit 0974d10

16 files changed

+675
-33
lines changed

chipflow_lib/steps/silicon.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,10 @@ def submit(self, rtlil_path, *, dry_run=False):
149149
logger.debug(f"padname={padname}, port={port}, loc={port.pins[0]}, "
150150
f"dir={port.direction}, width={width}")
151151
pads[padname] = {'loc': port.pins[0], 'type': port.direction.value}
152-
152+
153153
# Use the Pydantic models to access configuration data
154154
silicon_model = self.config_model.chipflow.silicon
155+
155156
config = {
156157
"dependency_versions": dep_versions,
157158
"silicon": {

docs/chipflow-toml-guide.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Let's start with a typical example:
1111
.. testcode::
1212
:hide:
1313

14-
# Assert that example-chipflow.toml matches the current config schema. If
14+
# Assert that example-chipflow.toml matches the current config schema. If
1515
# this test fails, then its likely that the content in this file will need
1616
# to be updated.
1717
from chipflow_lib import _parse_config_file
@@ -108,7 +108,7 @@ Available pad rings
108108
silicon.pads
109109
============
110110

111-
The ``silicon.pads`` section lists special pads. In general you are unlikely to need to add to this.
111+
The ``silicon.pads`` section lists special pads. In general you are unlikely to need to add to this.
112112

113113
For each pad, there's a label which is used by our design, and what ``type`` and ``loc`` each pad should be.
114114

tests/fixtures/mock_top.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,5 @@ def elaborate(self, platform):
4343
m = Module()
4444
for inpin, outpin in zip(self.test1.members, self.test2.members):
4545
m.d.comb += inpin.eq(outpin)
46-
46+
4747
return m

tests/test_buffers.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,49 +14,47 @@ class TestBuffers(unittest.TestCase):
1414
def test_io_buffer_mocked(self, mock_ffbuffer, mock_iobuffer):
1515
"""Test that IOBuffer can be imported and mocked"""
1616
from chipflow_lib.platforms.silicon import IOBuffer
17-
17+
1818
# Verify that the mock is working
1919
self.assertEqual(IOBuffer, mock_iobuffer)
20-
20+
2121
# Create a mock port
2222
port = mock.Mock()
2323
port.invert = False
24-
24+
2525
# Create a mock for the IOBuffer elaborate method
2626
module = Module()
2727
mock_iobuffer.return_value.elaborate.return_value = module
28-
28+
2929
# Create an IOBuffer instance
3030
buffer = IOBuffer(io.Direction.Input, port)
31-
31+
3232
# Elaborate the buffer
3333
result = buffer.elaborate(None)
34-
3534
# Verify the result
3635
self.assertEqual(result, module)
3736
mock_iobuffer.return_value.elaborate.assert_called_once()
3837

3938
def test_ff_buffer_mocked(self, mock_ffbuffer, mock_iobuffer):
4039
"""Test that FFBuffer can be imported and mocked"""
4140
from chipflow_lib.platforms.silicon import FFBuffer
42-
41+
4342
# Verify that the mock is working
4443
self.assertEqual(FFBuffer, mock_ffbuffer)
45-
44+
4645
# Create a mock port
4746
port = mock.Mock()
4847
port.invert = False
49-
48+
5049
# Create a mock for the FFBuffer elaborate method
5150
module = Module()
5251
mock_ffbuffer.return_value.elaborate.return_value = module
53-
52+
5453
# Create an FFBuffer instance
5554
buffer = FFBuffer(io.Direction.Input, port, i_domain="sync", o_domain="sync")
56-
55+
5756
# Elaborate the buffer
5857
result = buffer.elaborate(None)
59-
6058
# Verify the result
6159
self.assertEqual(result, module)
6260
mock_ffbuffer.return_value.elaborate.assert_called_once()

tests/test_cli.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ class MockCommand:
1515
def build_cli_parser(self, parser):
1616
parser.add_argument("--option", help="Test option")
1717
parser.add_argument("action", choices=["valid", "error", "unexpected"])
18+
<<<<<<< HEAD
1819

20+
=======
21+
22+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
1923
def run_cli(self, args):
2024
if args.action == "error":
2125
raise ChipFlowError("Command error")
@@ -39,18 +43,32 @@ def test_run_success(self, mock_get_cls, mock_pin_command, mock_parse_config):
3943
}
4044
}
4145
mock_parse_config.return_value = mock_config
46+
<<<<<<< HEAD
4247

4348
mock_pin_cmd = MockCommand()
4449
mock_pin_command.return_value = mock_pin_cmd
4550

4651
mock_test_cmd = MockCommand()
4752
mock_get_cls.return_value = lambda config: mock_test_cmd
4853

54+
=======
55+
56+
mock_pin_cmd = MockCommand()
57+
mock_pin_command.return_value = mock_pin_cmd
58+
59+
mock_test_cmd = MockCommand()
60+
mock_get_cls.return_value = lambda config: mock_test_cmd
61+
62+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
4963
# Capture stdout for assertion
5064
with mock.patch("sys.stdout") as mock_stdout:
5165
# Run with valid action
5266
run(["test", "valid"])
67+
<<<<<<< HEAD
5368

69+
=======
70+
71+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
5472
# No error message should be printed
5573
mock_stdout.write.assert_not_called()
5674

@@ -68,18 +86,32 @@ def test_run_command_error(self, mock_get_cls, mock_pin_command, mock_parse_conf
6886
}
6987
}
7088
mock_parse_config.return_value = mock_config
89+
<<<<<<< HEAD
7190

7291
mock_pin_cmd = MockCommand()
7392
mock_pin_command.return_value = mock_pin_cmd
7493

7594
mock_test_cmd = MockCommand()
7695
mock_get_cls.return_value = lambda config: mock_test_cmd
7796

97+
=======
98+
99+
mock_pin_cmd = MockCommand()
100+
mock_pin_command.return_value = mock_pin_cmd
101+
102+
mock_test_cmd = MockCommand()
103+
mock_get_cls.return_value = lambda config: mock_test_cmd
104+
105+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
78106
# Capture stdout for assertion
79107
with mock.patch("builtins.print") as mock_print:
80108
# Run with error action
81109
run(["test", "error"])
110+
<<<<<<< HEAD
82111

112+
=======
113+
114+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
83115
# Error message should be printed
84116
mock_print.assert_called_once()
85117
self.assertIn("Error while executing `test error`", mock_print.call_args[0][0])
@@ -98,18 +130,32 @@ def test_run_unexpected_error(self, mock_get_cls, mock_pin_command, mock_parse_c
98130
}
99131
}
100132
mock_parse_config.return_value = mock_config
133+
<<<<<<< HEAD
101134

102135
mock_pin_cmd = MockCommand()
103136
mock_pin_command.return_value = mock_pin_cmd
104137

105138
mock_test_cmd = MockCommand()
106139
mock_get_cls.return_value = lambda config: mock_test_cmd
107140

141+
=======
142+
143+
mock_pin_cmd = MockCommand()
144+
mock_pin_command.return_value = mock_pin_cmd
145+
146+
mock_test_cmd = MockCommand()
147+
mock_get_cls.return_value = lambda config: mock_test_cmd
148+
149+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
108150
# Capture stdout for assertion
109151
with mock.patch("builtins.print") as mock_print:
110152
# Run with unexpected error action
111153
run(["test", "unexpected"])
154+
<<<<<<< HEAD
112155

156+
=======
157+
158+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
113159
# Error message should be printed
114160
mock_print.assert_called_once()
115161
self.assertIn("Error while executing `test unexpected`", mock_print.call_args[0][0])
@@ -128,6 +174,7 @@ def test_step_init_error(self, mock_pin_command, mock_parse_config):
128174
}
129175
}
130176
mock_parse_config.return_value = mock_config
177+
<<<<<<< HEAD
131178

132179
mock_pin_cmd = MockCommand()
133180
mock_pin_command.return_value = mock_pin_cmd
@@ -139,6 +186,19 @@ def test_step_init_error(self, mock_pin_command, mock_parse_config):
139186
with self.assertRaises(ChipFlowError) as cm:
140187
run(["test", "valid"])
141188

189+
=======
190+
191+
mock_pin_cmd = MockCommand()
192+
mock_pin_command.return_value = mock_pin_cmd
193+
194+
# Make _get_cls_by_reference raise an exception during step initialization
195+
with mock.patch("chipflow_lib.cli._get_cls_by_reference") as mock_get_cls:
196+
mock_get_cls.return_value = mock.Mock(side_effect=Exception("Init error"))
197+
198+
with self.assertRaises(ChipFlowError) as cm:
199+
run(["test", "valid"])
200+
201+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
142202
self.assertIn("Encountered error while initializing step", str(cm.exception))
143203

144204
@mock.patch("chipflow_lib.cli._parse_config")
@@ -155,11 +215,16 @@ def test_build_parser_error(self, mock_get_cls, mock_pin_command, mock_parse_con
155215
}
156216
}
157217
mock_parse_config.return_value = mock_config
218+
<<<<<<< HEAD
158219

220+
=======
221+
222+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
159223
# Make pin command raise an error during build_cli_parser
160224
mock_pin_cmd = mock.Mock()
161225
mock_pin_cmd.build_cli_parser.side_effect = Exception("Parser error")
162226
mock_pin_command.return_value = mock_pin_cmd
227+
<<<<<<< HEAD
163228

164229
mock_test_cmd = mock.Mock()
165230
mock_test_cmd.build_cli_parser.side_effect = Exception("Parser error")
@@ -168,6 +233,16 @@ def test_build_parser_error(self, mock_get_cls, mock_pin_command, mock_parse_con
168233
with self.assertRaises(ChipFlowError) as cm:
169234
run(["pin", "lock"])
170235

236+
=======
237+
238+
mock_test_cmd = mock.Mock()
239+
mock_test_cmd.build_cli_parser.side_effect = Exception("Parser error")
240+
mock_get_cls.return_value = lambda config: mock_test_cmd
241+
242+
with self.assertRaises(ChipFlowError) as cm:
243+
run(["pin", "lock"])
244+
245+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
171246
self.assertIn("Encountered error while building CLI argument parser", str(cm.exception))
172247

173248
@mock.patch("chipflow_lib.cli._parse_config")
@@ -184,6 +259,7 @@ def test_verbosity_flags(self, mock_get_cls, mock_pin_command, mock_parse_config
184259
}
185260
}
186261
mock_parse_config.return_value = mock_config
262+
<<<<<<< HEAD
187263

188264
mock_pin_cmd = MockCommand()
189265
mock_pin_command.return_value = mock_pin_cmd
@@ -194,15 +270,34 @@ def test_verbosity_flags(self, mock_get_cls, mock_pin_command, mock_parse_config
194270
# Save original log level
195271
original_level = logging.getLogger().level
196272

273+
=======
274+
275+
mock_pin_cmd = MockCommand()
276+
mock_pin_command.return_value = mock_pin_cmd
277+
278+
mock_test_cmd = MockCommand()
279+
mock_get_cls.return_value = lambda config: mock_test_cmd
280+
281+
# Save original log level
282+
original_level = logging.getLogger().level
283+
284+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
197285
try:
198286
# Test with -v
199287
with mock.patch("sys.stdout"):
200288
run(["-v", "test", "valid"])
201289
self.assertEqual(logging.getLogger().level, logging.INFO)
290+
<<<<<<< HEAD
202291

203292
# Reset log level
204293
logging.getLogger().setLevel(original_level)
205294

295+
=======
296+
297+
# Reset log level
298+
logging.getLogger().setLevel(original_level)
299+
300+
>>>>>>> bd941c3 (Add comprehensive test suite for improved code coverage)
206301
# Test with -v -v
207302
with mock.patch("sys.stdout"):
208303
run(["-v", "-v", "test", "valid"])

tests/test_config.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
import os
3+
import unittest
4+
from unittest import mock
5+
6+
from chipflow_lib.config import get_dir_models, get_dir_software
7+
8+
9+
class TestConfig(unittest.TestCase):
10+
def test_get_dir_models(self):
11+
"""Test get_dir_models returns the correct path"""
12+
# Since we can't predict the absolute path, we'll check that it ends correctly
13+
models_dir = get_dir_models()
14+
self.assertTrue(models_dir.endswith("/chipflow_lib/models"))
15+
self.assertTrue(os.path.isdir(models_dir))
16+
17+
def test_get_dir_software(self):
18+
"""Test get_dir_software returns the correct path"""
19+
# Since we can't predict the absolute path, we'll check that it ends correctly
20+
software_dir = get_dir_software()
21+
self.assertTrue(software_dir.endswith("/chipflow_lib/software"))
22+
self.assertTrue(os.path.isdir(software_dir))

tests/test_errors.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
import unittest
3+
4+
from chipflow_lib.errors import ChipFlowError
5+
6+
7+
class TestErrors(unittest.TestCase):
8+
def test_chipflow_error(self):
9+
"""Test that ChipFlowError can be instantiated and raised"""
10+
# Test instantiation
11+
error = ChipFlowError("Test error message")
12+
self.assertEqual(str(error), "Test error message")
13+
14+
# Test raising
15+
with self.assertRaises(ChipFlowError) as cm:
16+
raise ChipFlowError("Test raised error")
17+
18+
self.assertEqual(str(cm.exception), "Test raised error")
19+
20+
# Test inheritance
21+
self.assertTrue(issubclass(ChipFlowError, Exception))

0 commit comments

Comments
 (0)