[PATCH 17/17] dtoc: Add tests for the pylibfdt bindings dtoc does not use

Alexey Charkov <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
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 <[email protected]>
---
 tools/dtoc/test_fdt.py | 175 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 174 insertions(+), 1 deletion(-)

diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index f141f931a949..4ab1365d5318 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -10,6 +10,7 @@ Written by Simon Glass <[email protected]>
 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)
 

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.