[Concept] buildman: Add tests for bsettings.py

Message ID 20251222041805.3157330-1-sjg@u-boot.org
State New
Headers
Series [Concept] buildman: Add tests for bsettings.py |

Commit Message

Simon Glass Dec. 22, 2025, 4:18 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a new test_bsettings.py with 12 tests to achieve 100% coverage for
bsettings.py

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 tools/buildman/main.py           |   3 +-
 tools/buildman/test_bsettings.py | 143 +++++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+), 1 deletion(-)
 create mode 100644 tools/buildman/test_bsettings.py
  

Patch

diff --git a/tools/buildman/main.py b/tools/buildman/main.py
index 9483e12e5d0..3c9820b262a 100755
--- a/tools/buildman/main.py
+++ b/tools/buildman/main.py
@@ -42,6 +42,7 @@  def run_tests(skip_net_tests, debug, verbose, args):
     from buildman import func_test
     from buildman import test
     from buildman import test_boards
+    from buildman import test_bsettings
 
     test_name = args.terms and args.terms[0] or None
     if skip_net_tests:
@@ -52,7 +53,7 @@  def run_tests(skip_net_tests, debug, verbose, args):
     result = test_util.run_test_suites(
         'buildman', debug, verbose, False, False, args.threads, test_name, [],
         [test.TestBuild, func_test.TestFunctional, test_boards.TestBoards,
-         'buildman.toolchain'])
+         test_bsettings.TestBsettings, 'buildman.toolchain'])
 
     return (0 if result.wasSuccessful() else 1)
 
diff --git a/tools/buildman/test_bsettings.py b/tools/buildman/test_bsettings.py
new file mode 100644
index 00000000000..524281f49b0
--- /dev/null
+++ b/tools/buildman/test_bsettings.py
@@ -0,0 +1,143 @@ 
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2024 Google, Inc
+
+"""Tests for bsettings.py"""
+
+import os
+import tempfile
+import unittest
+from unittest import mock
+
+from buildman import bsettings
+
+
+class TestBsettings(unittest.TestCase):
+    """Test bsettings module"""
+
+    def setUp(self):
+        self._tmpdir = tempfile.mkdtemp()
+
+    def tearDown(self):
+        import shutil
+        shutil.rmtree(self._tmpdir)
+
+    def test_setup_no_file(self):
+        """Test setup() with fname=None (no config file)"""
+        bsettings.setup(None)
+        # Should not raise, settings should be empty
+        self.assertEqual([], bsettings.get_items('nonexistent'))
+
+    def test_setup_default_missing(self):
+        """Test setup() creates config when default file missing"""
+        # Use a non-existent path for HOME
+        fake_home = os.path.join(self._tmpdir, 'fakehome')
+        os.makedirs(fake_home)
+        config_file = os.path.join(fake_home, '.buildman')
+
+        with mock.patch.dict(os.environ, {'HOME': fake_home}):
+            with mock.patch('builtins.print'):
+                bsettings.setup('')
+
+        # Config file should have been created
+        self.assertTrue(os.path.exists(config_file))
+
+    def test_setup_existing_file(self):
+        """Test setup() reads existing config file"""
+        config_file = os.path.join(self._tmpdir, 'test.buildman')
+        with open(config_file, 'w') as f:
+            f.write('[toolchain]\narm = /opt/arm\n')
+
+        bsettings.setup(config_file)
+        items = bsettings.get_items('toolchain')
+        self.assertEqual([('arm', '/opt/arm')], items)
+
+    def test_add_file(self):
+        """Test add_file() adds config data"""
+        bsettings.setup(None)
+        bsettings.add_file('[test]\nkey = value\n')
+        items = bsettings.get_items('test')
+        self.assertEqual([('key', 'value')], items)
+
+    def test_add_section(self):
+        """Test add_section() creates new section"""
+        bsettings.setup(None)
+        bsettings.add_section('newsection')
+        # Section should exist but be empty
+        self.assertEqual([], bsettings.get_items('newsection'))
+
+    def test_get_items_missing_section(self):
+        """Test get_items() returns empty list for missing section"""
+        bsettings.setup(None)
+        self.assertEqual([], bsettings.get_items('nonexistent'))
+
+    def test_get_items_other_error(self):
+        """Test get_items() re-raises non-NoSectionError exceptions"""
+        bsettings.setup(None)
+        with mock.patch.object(bsettings.settings, 'items',
+                               side_effect=ValueError('test error')):
+            with self.assertRaises(ValueError):
+                bsettings.get_items('test')
+
+    def test_get_global_item_value(self):
+        """Test get_global_item_value() retrieves global items"""
+        bsettings.setup(None)
+        bsettings.add_file('[global]\nmykey = myvalue\n')
+        self.assertEqual('myvalue', bsettings.get_global_item_value('mykey'))
+        self.assertIsNone(bsettings.get_global_item_value('missing'))
+
+    def test_set_item(self):
+        """Test set_item() sets value and writes to file"""
+        config_file = os.path.join(self._tmpdir, 'test_set.buildman')
+        with open(config_file, 'w') as f:
+            f.write('[toolchain]\n')
+
+        bsettings.setup(config_file)
+        bsettings.set_item('toolchain', 'newkey', 'newvalue')
+
+        # Value should be set in memory
+        items = dict(bsettings.get_items('toolchain'))
+        self.assertEqual('newvalue', items['newkey'])
+
+        # Value should be written to file
+        with open(config_file) as f:
+            content = f.read()
+        self.assertIn('newkey', content)
+        self.assertIn('newvalue', content)
+
+    def test_set_item_no_file(self):
+        """Test set_item() when config_fname is None"""
+        # Explicitly reset config_fname to None
+        bsettings.config_fname = None
+        bsettings.setup(None)
+        bsettings.add_section('test')
+        # Should not raise even though there's no file to write
+        bsettings.set_item('test', 'key', 'value')
+        items = dict(bsettings.get_items('test'))
+        self.assertEqual('value', items['key'])
+
+    def test_create_buildman_config_file(self):
+        """Test create_buildman_config_file() creates valid config"""
+        config_file = os.path.join(self._tmpdir, 'new.buildman')
+
+        bsettings.create_buildman_config_file(config_file)
+
+        self.assertTrue(os.path.exists(config_file))
+        with open(config_file) as f:
+            content = f.read()
+        self.assertIn('[toolchain]', content)
+        self.assertIn('[toolchain-prefix]', content)
+        self.assertIn('[toolchain-alias]', content)
+        self.assertIn('[make-flags]', content)
+
+    def test_create_buildman_config_file_error(self):
+        """Test create_buildman_config_file() handles IOError"""
+        # Try to create file in non-existent directory
+        bad_path = '/nonexistent/path/config'
+
+        with mock.patch('builtins.print'):
+            with self.assertRaises(IOError):
+                bsettings.create_buildman_config_file(bad_path)
+
+
+if __name__ == '__main__':
+    unittest.main()