summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Charkov <alchark@flipper.net>2026-08-24 17:13:14 +0400
committerTom Rini <trini@konsulko.com>2026-08-31 17:06:21 -0600
commit01fb2b4d7368483f95b6018b2c069de0b8ebadeb (patch)
treed5d4a00642f1c9304e48cf3619a40dc2e03f0d4f
parent44a2a718fbe62d703a8ce2ff576d2252c7444087 (diff)
downloadu-boot-01fb2b4d7368483f95b6018b2c069de0b8ebadeb.tar.gz
u-boot-01fb2b4d7368483f95b6018b2c069de0b8ebadeb.zip
dtoc: Add tests for the pylibfdt bindings dtoc does not use
Exercise additional pylibfdt bindings imported from upstream against the existing dtoc test tree, which already carries a boolean property, a string list, integer arrays and a bus node that overrides #address-cells and #size-cells. The FdtSw cases cover both halves of the geometric growth change: that an out-of-space result at least doubles the buffer, and that a tree needing several expansions still comes out intact. Signed-off-by: Alexey Charkov <alchark@flipper.net>
-rwxr-xr-xtools/dtoc/test_fdt.py175
1 files changed, 174 insertions, 1 deletions
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index f141f931a94..4ab1365d531 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -10,6 +10,7 @@ Written by Simon Glass <sjg@chromium.org>
from argparse import ArgumentParser
import os
import shutil
+import struct
import sys
import tempfile
import unittest
@@ -754,6 +755,178 @@ class TestProp(unittest.TestCase):
self.dtb.GetFilename())
+class TestPylibfdt(unittest.TestCase):
+ """Tests for the parts of pylibfdt that dtoc does not itself use
+
+ These bindings come from upstream dtc and have no coverage elsewhere in
+ U-Boot, so exercise them directly rather than through the Fdt wrapper.
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ tools.prepare_output_dir(None)
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.finalise_output_dir()
+
+ def setUp(self):
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
+ self.fdt = self.dtb.GetFdtObj()
+ self.node = self.fdt.path_offset('/spl-test')
+
+ def test_hasprop(self):
+ """Test checking for the presence of a property"""
+ self.assertTrue(self.fdt.hasprop(self.node, 'boolval'))
+ self.assertTrue(self.fdt.hasprop(self.node, 'intval'))
+ self.assertFalse(self.fdt.hasprop(self.node, 'missing'))
+
+ def test_hasprop_bad_node(self):
+ """Test that hasprop() still reports errors other than NOTFOUND"""
+ with self.assertRaises(libfdt.FdtException) as exc:
+ self.fdt.hasprop(-1, 'boolval')
+ self.assertEqual(-libfdt.BADOFFSET, exc.exception.err)
+
+ def test_setprop_bool(self):
+ """Test creating and deleting a boolean property"""
+ # Leave room for the new property
+ self.fdt.resize(self.fdt.totalsize() + 1024)
+ node = self.fdt.path_offset('/spl-test')
+
+ self.fdt.setprop_bool(node, 'newbool', True)
+ self.assertTrue(self.fdt.hasprop(node, 'newbool'))
+ self.assertEqual(b'', self.fdt.getprop(node, 'newbool'))
+
+ # Setting it again should be a no-op
+ self.fdt.setprop_bool(node, 'newbool', True)
+ self.assertTrue(self.fdt.hasprop(node, 'newbool'))
+
+ self.fdt.setprop_bool(node, 'newbool', False)
+ self.assertFalse(self.fdt.hasprop(node, 'newbool'))
+
+ # Deleting it again should also be a no-op
+ self.fdt.setprop_bool(node, 'newbool', False)
+ self.assertFalse(self.fdt.hasprop(node, 'newbool'))
+
+ def test_get_path(self):
+ """Test reading back the full path of a node"""
+ node = self.fdt.path_offset('/i2c@0/pmic@9')
+ self.assertEqual('/i2c@0/pmic@9', self.fdt.get_path(node))
+ self.assertEqual('/', self.fdt.get_path(0))
+
+ def test_get_path_no_space(self):
+ """Test that get_path() retries with a larger buffer as needed"""
+ node = self.fdt.path_offset('/i2c@0/pmic@9')
+ self.assertEqual('/i2c@0/pmic@9', self.fdt.get_path(node, size_hint=1))
+
+ def test_get_path_bad_node(self):
+ """Test get_path() on an invalid node offset"""
+ with self.assertRaises(libfdt.FdtException) as exc:
+ self.fdt.get_path(-1)
+ self.assertEqual(-libfdt.BADOFFSET, exc.exception.err)
+
+ def test_as_stringlist(self):
+ """Test decoding a string-list property"""
+ prop = self.fdt.getprop(self.node, 'stringarray')
+ self.assertEqual(['multi-word', 'message'], prop.as_stringlist())
+
+ prop = self.fdt.getprop(self.node, 'stringval')
+ self.assertEqual(['message'], prop.as_stringlist())
+
+ def test_as_int_lists(self):
+ """Test decoding integer-array properties"""
+ prop = self.fdt.getprop(self.node, 'intarray')
+ self.assertEqual([2, 3, 4], prop.as_uint32_list())
+ self.assertEqual([2, 3, 4], prop.as_int32_list())
+
+ prop = self.fdt.getprop(self.node, 'int64val')
+ self.assertEqual([0x123456789abcdef0], prop.as_uint64_list())
+ self.assertEqual([0x123456789abcdef0], prop.as_int64_list())
+
+ def test_as_int_lists_negative(self):
+ """Test that the signed accessors differ from the unsigned ones"""
+ self.fdt.resize(self.fdt.totalsize() + 1024)
+ node = self.fdt.path_offset('/spl-test')
+
+ self.fdt.setprop(node, 'negs32', struct.pack('>ll', -1, -2))
+ prop = self.fdt.getprop(node, 'negs32')
+ self.assertEqual([-1, -2], prop.as_int32_list())
+ self.assertEqual([0xffffffff, 0xfffffffe], prop.as_uint32_list())
+
+ self.fdt.setprop(node, 'negs64', struct.pack('>qq', -1, -2))
+ prop = self.fdt.getprop(node, 'negs64')
+ self.assertEqual([-1, -2], prop.as_int64_list())
+ self.assertEqual([0xffffffffffffffff, 0xfffffffffffffffe],
+ prop.as_uint64_list())
+
+ def test_address_and_size_cells(self):
+ """Test reading the cell counts a node uses for its children"""
+ self.assertEqual(1, self.fdt.address_cells(0))
+ self.assertEqual(1, self.fdt.size_cells(0))
+
+ # i2c@0 overrides both
+ i2c = self.fdt.path_offset('/i2c@0')
+ self.assertEqual(1, self.fdt.address_cells(i2c))
+ self.assertEqual(0, self.fdt.size_cells(i2c))
+
+ def test_mem_rsv(self):
+ """Test adding, reading back and deleting reserve-map records"""
+ self.assertEqual(0, self.fdt.num_mem_rsv())
+
+ # Leave room for the new records
+ self.fdt.resize(self.fdt.totalsize() + 1024)
+ self.fdt.add_mem_rsv(0xdeadbeef00000000, 0x100000)
+ self.fdt.add_mem_rsv(0x1000, 0x2000)
+ self.assertEqual(2, self.fdt.num_mem_rsv())
+ self.assertEqual([0xdeadbeef00000000, 0x100000],
+ list(self.fdt.get_mem_rsv(0)))
+ self.assertEqual([0x1000, 0x2000], list(self.fdt.get_mem_rsv(1)))
+
+ self.fdt.del_mem_rsv(0)
+ self.assertEqual(1, self.fdt.num_mem_rsv())
+ self.assertEqual([0x1000, 0x2000], list(self.fdt.get_mem_rsv(0)))
+
+ def test_del_mem_rsv_missing(self):
+ """Test deleting a reserve-map record which is not there"""
+ with self.assertRaises(libfdt.FdtException) as exc:
+ self.fdt.del_mem_rsv(0)
+ self.assertEqual(-libfdt.NOTFOUND, exc.exception.err)
+
+ def test_fdtsw_growth(self):
+ """Test that running out of space at least doubles the buffer"""
+ fdtsw = libfdt.FdtSw()
+ size = len(fdtsw._fdt)
+ self.assertEqual(fdtsw.INC_SIZE, size)
+
+ self.assertTrue(fdtsw.check_space(-libfdt.NOSPACE))
+ self.assertEqual(size * 2, len(fdtsw._fdt))
+
+ self.assertTrue(fdtsw.check_space(-libfdt.NOSPACE))
+ self.assertEqual(size * 4, len(fdtsw._fdt))
+
+ # Anything that is not an out-of-space error leaves the buffer alone
+ self.assertFalse(fdtsw.check_space(0))
+ self.assertEqual(size * 4, len(fdtsw._fdt))
+
+ def test_fdtsw_build(self):
+ """Test building a tree large enough to need several expansions"""
+ fdtsw = libfdt.FdtSw()
+ fdtsw.finish_reservemap()
+ fdtsw.begin_node('')
+ for i in range(50):
+ fdtsw.begin_node(f'node{i}')
+ fdtsw.property('data', b'x' * 200)
+ fdtsw.end_node()
+ fdtsw.end_node()
+
+ out = fdtsw.as_fdt()
+ self.assertGreater(out.totalsize(), fdtsw.INC_SIZE * 4)
+ for i in range(50):
+ node = out.path_offset(f'/node{i}')
+ self.assertEqual(f'/node{i}', out.get_path(node))
+ self.assertEqual(b'x' * 200, out.getprop(node, 'data'))
+
+
class TestFdtUtil(unittest.TestCase):
"""Tests for the fdt_util module
@@ -970,7 +1143,7 @@ def run_tests(names, processes):
test_name = names[0] if names else None
result = test_util.run_test_suites(
'test_fdt', False, False, False, False, processes, test_name, None,
- [TestFdt, TestNode, TestProp, TestFdtUtil])
+ [TestFdt, TestNode, TestProp, TestPylibfdt, TestFdtUtil])
return (0 if result.wasSuccessful() else 1)