xref: /openbmc/u-boot/tools/dtoc/test_fdt.py (revision cf033e04)
12ba98753SSimon Glass#!/usr/bin/python
22ba98753SSimon Glass# SPDX-License-Identifier: GPL-2.0+
32ba98753SSimon Glass# Copyright (c) 2018 Google, Inc
42ba98753SSimon Glass# Written by Simon Glass <sjg@chromium.org>
52ba98753SSimon Glass#
62ba98753SSimon Glass
72ba98753SSimon Glassfrom optparse import OptionParser
82ba98753SSimon Glassimport glob
92ba98753SSimon Glassimport os
102ba98753SSimon Glassimport sys
112ba98753SSimon Glassimport unittest
122ba98753SSimon Glass
132ba98753SSimon Glass# Bring in the patman libraries
142ba98753SSimon Glassour_path = os.path.dirname(os.path.realpath(__file__))
152ba98753SSimon Glassfor dirname in ['../patman', '..']:
162ba98753SSimon Glass    sys.path.insert(0, os.path.join(our_path, dirname))
172ba98753SSimon Glass
182ba98753SSimon Glassimport command
192ba98753SSimon Glassimport fdt
202ba98753SSimon Glassfrom fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL
212a2d91d0SSimon Glassimport fdt_util
222ba98753SSimon Glassfrom fdt_util import fdt32_to_cpu
232ba98753SSimon Glassimport libfdt
242ba98753SSimon Glassimport test_util
252ba98753SSimon Glassimport tools
262ba98753SSimon Glass
27f9b88b3aSSimon Glassdef _GetPropertyValue(dtb, node, prop_name):
28f9b88b3aSSimon Glass    """Low-level function to get the property value based on its offset
29f9b88b3aSSimon Glass
30f9b88b3aSSimon Glass    This looks directly in the device tree at the property's offset to find
31f9b88b3aSSimon Glass    its value. It is useful as a check that the property is in the correct
32f9b88b3aSSimon Glass    place.
33f9b88b3aSSimon Glass
34f9b88b3aSSimon Glass    Args:
35f9b88b3aSSimon Glass        node: Node to look in
36f9b88b3aSSimon Glass        prop_name: Property name to find
37f9b88b3aSSimon Glass
38f9b88b3aSSimon Glass    Returns:
39f9b88b3aSSimon Glass        Tuple:
40f9b88b3aSSimon Glass            Prop object found
41f9b88b3aSSimon Glass            Value of property as a string (found using property offset)
42f9b88b3aSSimon Glass    """
43f9b88b3aSSimon Glass    prop = node.props[prop_name]
44f9b88b3aSSimon Glass
45f9b88b3aSSimon Glass    # Add 12, which is sizeof(struct fdt_property), to get to start of data
46f9b88b3aSSimon Glass    offset = prop.GetOffset() + 12
47f9b88b3aSSimon Glass    data = dtb.GetContents()[offset:offset + len(prop.value)]
48f9b88b3aSSimon Glass    return prop, [chr(x) for x in data]
49f9b88b3aSSimon Glass
50f9b88b3aSSimon Glass
512ba98753SSimon Glassclass TestFdt(unittest.TestCase):
522ba98753SSimon Glass    """Tests for the Fdt module
532ba98753SSimon Glass
542ba98753SSimon Glass    This includes unit tests for some functions and functional tests for the fdt
552ba98753SSimon Glass    module.
562ba98753SSimon Glass    """
572ba98753SSimon Glass    @classmethod
582ba98753SSimon Glass    def setUpClass(cls):
592ba98753SSimon Glass        tools.PrepareOutputDir(None)
602ba98753SSimon Glass
612ba98753SSimon Glass    @classmethod
622ba98753SSimon Glass    def tearDownClass(cls):
63e0e6275fSSimon Glass        tools.FinaliseOutputDir()
642ba98753SSimon Glass
652ba98753SSimon Glass    def setUp(self):
662ba98753SSimon Glass        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
672ba98753SSimon Glass
682ba98753SSimon Glass    def testFdt(self):
692ba98753SSimon Glass        """Test that we can open an Fdt"""
702ba98753SSimon Glass        self.dtb.Scan()
712ba98753SSimon Glass        root = self.dtb.GetRoot()
722ba98753SSimon Glass        self.assertTrue(isinstance(root, fdt.Node))
732ba98753SSimon Glass
742ba98753SSimon Glass    def testGetNode(self):
752ba98753SSimon Glass        """Test the GetNode() method"""
762ba98753SSimon Glass        node = self.dtb.GetNode('/spl-test')
772ba98753SSimon Glass        self.assertTrue(isinstance(node, fdt.Node))
782ba98753SSimon Glass        node = self.dtb.GetNode('/i2c@0/pmic@9')
792ba98753SSimon Glass        self.assertTrue(isinstance(node, fdt.Node))
802ba98753SSimon Glass        self.assertEqual('pmic@9', node.name)
812a2d91d0SSimon Glass        self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
822ba98753SSimon Glass
832ba98753SSimon Glass    def testFlush(self):
842ba98753SSimon Glass        """Check that we can flush the device tree out to its file"""
852ba98753SSimon Glass        fname = self.dtb._fname
862ba98753SSimon Glass        with open(fname) as fd:
872ba98753SSimon Glass            data = fd.read()
882ba98753SSimon Glass        os.remove(fname)
892ba98753SSimon Glass        with self.assertRaises(IOError):
902ba98753SSimon Glass            open(fname)
912ba98753SSimon Glass        self.dtb.Flush()
922ba98753SSimon Glass        with open(fname) as fd:
932ba98753SSimon Glass            data = fd.read()
942ba98753SSimon Glass
952ba98753SSimon Glass    def testPack(self):
962ba98753SSimon Glass        """Test that packing a device tree works"""
972ba98753SSimon Glass        self.dtb.Pack()
982ba98753SSimon Glass
992ba98753SSimon Glass    def testGetFdt(self):
1002ba98753SSimon Glass        """Tetst that we can access the raw device-tree data"""
10196066240SSimon Glass        self.assertTrue(isinstance(self.dtb.GetContents(), bytearray))
1022ba98753SSimon Glass
1032ba98753SSimon Glass    def testGetProps(self):
1042ba98753SSimon Glass        """Tests obtaining a list of properties"""
1052ba98753SSimon Glass        node = self.dtb.GetNode('/spl-test')
1062ba98753SSimon Glass        props = self.dtb.GetProps(node)
1072ba98753SSimon Glass        self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
1082a2d91d0SSimon Glass                          'intarray', 'intval', 'longbytearray', 'notstring',
1092ba98753SSimon Glass                          'stringarray', 'stringval', 'u-boot,dm-pre-reloc'],
1102ba98753SSimon Glass                         sorted(props.keys()))
1112ba98753SSimon Glass
1122ba98753SSimon Glass    def testCheckError(self):
1132ba98753SSimon Glass        """Tests the ChecKError() function"""
1142ba98753SSimon Glass        with self.assertRaises(ValueError) as e:
1152a2d91d0SSimon Glass            fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
1162ba98753SSimon Glass        self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
1172ba98753SSimon Glass
11894a7c603SSimon Glass    def testGetFdt(self):
11994a7c603SSimon Glass        node = self.dtb.GetNode('/spl-test')
12094a7c603SSimon Glass        self.assertEqual(self.dtb, node.GetFdt())
1212ba98753SSimon Glass
1222ba98753SSimon Glassclass TestNode(unittest.TestCase):
1232ba98753SSimon Glass    """Test operation of the Node class"""
1242ba98753SSimon Glass
1252ba98753SSimon Glass    @classmethod
1262ba98753SSimon Glass    def setUpClass(cls):
1272ba98753SSimon Glass        tools.PrepareOutputDir(None)
1282ba98753SSimon Glass
1292ba98753SSimon Glass    @classmethod
1302ba98753SSimon Glass    def tearDownClass(cls):
131e0e6275fSSimon Glass        tools.FinaliseOutputDir()
1322ba98753SSimon Glass
1332ba98753SSimon Glass    def setUp(self):
1342ba98753SSimon Glass        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
1352ba98753SSimon Glass        self.node = self.dtb.GetNode('/spl-test')
1362ba98753SSimon Glass
1372ba98753SSimon Glass    def testOffset(self):
1382ba98753SSimon Glass        """Tests that we can obtain the offset of a node"""
1392ba98753SSimon Glass        self.assertTrue(self.node.Offset() > 0)
1402ba98753SSimon Glass
1412ba98753SSimon Glass    def testDelete(self):
1422ba98753SSimon Glass        """Tests that we can delete a property"""
1432ba98753SSimon Glass        node2 = self.dtb.GetNode('/spl-test2')
1442ba98753SSimon Glass        offset1 = node2.Offset()
1452ba98753SSimon Glass        self.node.DeleteProp('intval')
1462ba98753SSimon Glass        offset2 = node2.Offset()
1472ba98753SSimon Glass        self.assertTrue(offset2 < offset1)
1482ba98753SSimon Glass        self.node.DeleteProp('intarray')
1492ba98753SSimon Glass        offset3 = node2.Offset()
1502ba98753SSimon Glass        self.assertTrue(offset3 < offset2)
1512a2d91d0SSimon Glass        with self.assertRaises(libfdt.FdtException):
1522a2d91d0SSimon Glass            self.node.DeleteProp('missing')
1532ba98753SSimon Glass
154f9b88b3aSSimon Glass    def testDeleteGetOffset(self):
155f9b88b3aSSimon Glass        """Test that property offset update when properties are deleted"""
156f9b88b3aSSimon Glass        self.node.DeleteProp('intval')
157f9b88b3aSSimon Glass        prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
158f9b88b3aSSimon Glass        self.assertEqual(prop.value, value)
159f9b88b3aSSimon Glass
1602ba98753SSimon Glass    def testFindNode(self):
1611d85888cSSimon Glass        """Tests that we can find a node using the FindNode() functoin"""
1621d85888cSSimon Glass        node = self.dtb.GetRoot().FindNode('i2c@0')
1632ba98753SSimon Glass        self.assertEqual('i2c@0', node.name)
1641d85888cSSimon Glass        subnode = node.FindNode('pmic@9')
1652ba98753SSimon Glass        self.assertEqual('pmic@9', subnode.name)
1661d85888cSSimon Glass        self.assertEqual(None, node.FindNode('missing'))
1672ba98753SSimon Glass
168f9b88b3aSSimon Glass    def testRefreshMissingNode(self):
169f9b88b3aSSimon Glass        """Test refreshing offsets when an extra node is present in dtb"""
170f9b88b3aSSimon Glass        # Delete it from our tables, not the device tree
171f9b88b3aSSimon Glass        del self.dtb._root.subnodes[-1]
172f9b88b3aSSimon Glass        with self.assertRaises(ValueError) as e:
173f9b88b3aSSimon Glass            self.dtb.Refresh()
174f9b88b3aSSimon Glass        self.assertIn('Internal error, offset', str(e.exception))
175f9b88b3aSSimon Glass
176f9b88b3aSSimon Glass    def testRefreshExtraNode(self):
177f9b88b3aSSimon Glass        """Test refreshing offsets when an expected node is missing"""
178f9b88b3aSSimon Glass        # Delete it from the device tre, not our tables
179f9b88b3aSSimon Glass        self.dtb.GetFdtObj().del_node(self.node.Offset())
180f9b88b3aSSimon Glass        with self.assertRaises(ValueError) as e:
181f9b88b3aSSimon Glass            self.dtb.Refresh()
182f9b88b3aSSimon Glass        self.assertIn('Internal error, node name mismatch '
183f9b88b3aSSimon Glass                      'spl-test != spl-test2', str(e.exception))
184f9b88b3aSSimon Glass
185f9b88b3aSSimon Glass    def testRefreshMissingProp(self):
186f9b88b3aSSimon Glass        """Test refreshing offsets when an extra property is present in dtb"""
187f9b88b3aSSimon Glass        # Delete it from our tables, not the device tree
188f9b88b3aSSimon Glass        del self.node.props['notstring']
189f9b88b3aSSimon Glass        with self.assertRaises(ValueError) as e:
190f9b88b3aSSimon Glass            self.dtb.Refresh()
191f9b88b3aSSimon Glass        self.assertIn("Internal error, property 'notstring' missing, offset ",
192f9b88b3aSSimon Glass                      str(e.exception))
193f9b88b3aSSimon Glass
19494a7c603SSimon Glass    def testLookupPhandle(self):
19594a7c603SSimon Glass        """Test looking up a single phandle"""
19694a7c603SSimon Glass        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
19794a7c603SSimon Glass        node = dtb.GetNode('/phandle-source2')
19894a7c603SSimon Glass        prop = node.props['clocks']
19994a7c603SSimon Glass        target = dtb.GetNode('/phandle-target')
20094a7c603SSimon Glass        self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
20194a7c603SSimon Glass
2022ba98753SSimon Glass
2032ba98753SSimon Glassclass TestProp(unittest.TestCase):
2042ba98753SSimon Glass    """Test operation of the Prop class"""
2052ba98753SSimon Glass
2062ba98753SSimon Glass    @classmethod
2072ba98753SSimon Glass    def setUpClass(cls):
2082ba98753SSimon Glass        tools.PrepareOutputDir(None)
2092ba98753SSimon Glass
2102ba98753SSimon Glass    @classmethod
2112ba98753SSimon Glass    def tearDownClass(cls):
212e0e6275fSSimon Glass        tools.FinaliseOutputDir()
2132ba98753SSimon Glass
2142ba98753SSimon Glass    def setUp(self):
2152ba98753SSimon Glass        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
2162ba98753SSimon Glass        self.node = self.dtb.GetNode('/spl-test')
2172ba98753SSimon Glass        self.fdt = self.dtb.GetFdtObj()
2182ba98753SSimon Glass
219b9066ffcSSimon Glass    def testMissingNode(self):
220b9066ffcSSimon Glass        self.assertEqual(None, self.dtb.GetNode('missing'))
221b9066ffcSSimon Glass
2222a2d91d0SSimon Glass    def testPhandle(self):
2232a2d91d0SSimon Glass        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
224760b7170SSimon Glass        node = dtb.GetNode('/phandle-source2')
225760b7170SSimon Glass        prop = node.props['clocks']
226760b7170SSimon Glass        self.assertTrue(fdt32_to_cpu(prop.value) > 0)
2272a2d91d0SSimon Glass
2282a2d91d0SSimon Glass    def _ConvertProp(self, prop_name):
2292a2d91d0SSimon Glass        """Helper function to look up a property in self.node and return it
2302a2d91d0SSimon Glass
2312a2d91d0SSimon Glass        Args:
2322a2d91d0SSimon Glass            Property name to find
2332a2d91d0SSimon Glass
2342a2d91d0SSimon Glass        Return fdt.Prop object for this property
2352a2d91d0SSimon Glass        """
23650c59522SSimon Glass        p = self.fdt.getprop(self.node.Offset(), prop_name)
2372a2d91d0SSimon Glass        return fdt.Prop(self.node, -1, prop_name, p)
2382a2d91d0SSimon Glass
2392a2d91d0SSimon Glass    def testMakeProp(self):
2402a2d91d0SSimon Glass        """Test we can convert all the the types that are supported"""
2412a2d91d0SSimon Glass        prop = self._ConvertProp('boolval')
2422a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_BOOL, prop.type)
2432a2d91d0SSimon Glass        self.assertEqual(True, prop.value)
2442a2d91d0SSimon Glass
2452a2d91d0SSimon Glass        prop = self._ConvertProp('intval')
2462a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_INT, prop.type)
2472a2d91d0SSimon Glass        self.assertEqual(1, fdt32_to_cpu(prop.value))
2482a2d91d0SSimon Glass
2492a2d91d0SSimon Glass        prop = self._ConvertProp('intarray')
2502a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_INT, prop.type)
2512a2d91d0SSimon Glass        val = [fdt32_to_cpu(val) for val in prop.value]
2522a2d91d0SSimon Glass        self.assertEqual([2, 3, 4], val)
2532a2d91d0SSimon Glass
2542a2d91d0SSimon Glass        prop = self._ConvertProp('byteval')
2552a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_BYTE, prop.type)
2562a2d91d0SSimon Glass        self.assertEqual(5, ord(prop.value))
2572a2d91d0SSimon Glass
2582a2d91d0SSimon Glass        prop = self._ConvertProp('longbytearray')
2592a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_BYTE, prop.type)
2602a2d91d0SSimon Glass        val = [ord(val) for val in prop.value]
2612a2d91d0SSimon Glass        self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
2622a2d91d0SSimon Glass
2632a2d91d0SSimon Glass        prop = self._ConvertProp('stringval')
2642a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_STRING, prop.type)
2652a2d91d0SSimon Glass        self.assertEqual('message', prop.value)
2662a2d91d0SSimon Glass
2672a2d91d0SSimon Glass        prop = self._ConvertProp('stringarray')
2682a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_STRING, prop.type)
2692a2d91d0SSimon Glass        self.assertEqual(['multi-word', 'message'], prop.value)
2702a2d91d0SSimon Glass
2712a2d91d0SSimon Glass        prop = self._ConvertProp('notstring')
2722a2d91d0SSimon Glass        self.assertEqual(fdt.TYPE_BYTE, prop.type)
2732a2d91d0SSimon Glass        val = [ord(val) for val in prop.value]
2742a2d91d0SSimon Glass        self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
2752a2d91d0SSimon Glass
2762ba98753SSimon Glass    def testGetEmpty(self):
2772ba98753SSimon Glass        """Tests the GetEmpty() function for the various supported types"""
2782ba98753SSimon Glass        self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL))
2792ba98753SSimon Glass        self.assertEqual(chr(0), fdt.Prop.GetEmpty(fdt.TYPE_BYTE))
2802ba98753SSimon Glass        self.assertEqual(chr(0) * 4, fdt.Prop.GetEmpty(fdt.TYPE_INT))
2812ba98753SSimon Glass        self.assertEqual('', fdt.Prop.GetEmpty(fdt.TYPE_STRING))
2822ba98753SSimon Glass
2832ba98753SSimon Glass    def testGetOffset(self):
2842ba98753SSimon Glass        """Test we can get the offset of a property"""
285f9b88b3aSSimon Glass        prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
286f9b88b3aSSimon Glass        self.assertEqual(prop.value, value)
2872ba98753SSimon Glass
2882ba98753SSimon Glass    def testWiden(self):
2892ba98753SSimon Glass        """Test widening of values"""
2902ba98753SSimon Glass        node2 = self.dtb.GetNode('/spl-test2')
2912ba98753SSimon Glass        prop = self.node.props['intval']
2922ba98753SSimon Glass
2932ba98753SSimon Glass        # No action
2942ba98753SSimon Glass        prop2 = node2.props['intval']
2952ba98753SSimon Glass        prop.Widen(prop2)
2962ba98753SSimon Glass        self.assertEqual(fdt.TYPE_INT, prop.type)
2972ba98753SSimon Glass        self.assertEqual(1, fdt32_to_cpu(prop.value))
2982ba98753SSimon Glass
2992ba98753SSimon Glass        # Convert singla value to array
3002ba98753SSimon Glass        prop2 = self.node.props['intarray']
3012ba98753SSimon Glass        prop.Widen(prop2)
3022ba98753SSimon Glass        self.assertEqual(fdt.TYPE_INT, prop.type)
3032ba98753SSimon Glass        self.assertTrue(isinstance(prop.value, list))
3042ba98753SSimon Glass
3052ba98753SSimon Glass        # A 4-byte array looks like a single integer. When widened by a longer
3062ba98753SSimon Glass        # byte array, it should turn into an array.
3072ba98753SSimon Glass        prop = self.node.props['longbytearray']
3082ba98753SSimon Glass        prop2 = node2.props['longbytearray']
3092ba98753SSimon Glass        self.assertFalse(isinstance(prop2.value, list))
3102ba98753SSimon Glass        self.assertEqual(4, len(prop2.value))
3112ba98753SSimon Glass        prop2.Widen(prop)
3122ba98753SSimon Glass        self.assertTrue(isinstance(prop2.value, list))
3132ba98753SSimon Glass        self.assertEqual(9, len(prop2.value))
3142ba98753SSimon Glass
3152ba98753SSimon Glass        # Similarly for a string array
3162ba98753SSimon Glass        prop = self.node.props['stringval']
3172ba98753SSimon Glass        prop2 = node2.props['stringarray']
3182ba98753SSimon Glass        self.assertFalse(isinstance(prop.value, list))
3192ba98753SSimon Glass        self.assertEqual(7, len(prop.value))
3202ba98753SSimon Glass        prop.Widen(prop2)
3212ba98753SSimon Glass        self.assertTrue(isinstance(prop.value, list))
3222ba98753SSimon Glass        self.assertEqual(3, len(prop.value))
3232ba98753SSimon Glass
3242ba98753SSimon Glass        # Enlarging an existing array
3252ba98753SSimon Glass        prop = self.node.props['stringarray']
3262ba98753SSimon Glass        prop2 = node2.props['stringarray']
3272ba98753SSimon Glass        self.assertTrue(isinstance(prop.value, list))
3282ba98753SSimon Glass        self.assertEqual(2, len(prop.value))
3292ba98753SSimon Glass        prop.Widen(prop2)
3302ba98753SSimon Glass        self.assertTrue(isinstance(prop.value, list))
3312ba98753SSimon Glass        self.assertEqual(3, len(prop.value))
3322ba98753SSimon Glass
333116adecbSSimon Glass    def testAdd(self):
334116adecbSSimon Glass        """Test adding properties"""
335116adecbSSimon Glass        self.fdt.pack()
336116adecbSSimon Glass        # This function should automatically expand the device tree
337116adecbSSimon Glass        self.node.AddZeroProp('one')
338116adecbSSimon Glass        self.node.AddZeroProp('two')
339116adecbSSimon Glass        self.node.AddZeroProp('three')
340fa80c25cSSimon Glass        self.dtb.Sync(auto_resize=True)
341116adecbSSimon Glass
342116adecbSSimon Glass        # Updating existing properties should be OK, since the device-tree size
343116adecbSSimon Glass        # does not change
344116adecbSSimon Glass        self.fdt.pack()
345116adecbSSimon Glass        self.node.SetInt('one', 1)
346116adecbSSimon Glass        self.node.SetInt('two', 2)
347116adecbSSimon Glass        self.node.SetInt('three', 3)
348fa80c25cSSimon Glass        self.dtb.Sync(auto_resize=False)
349116adecbSSimon Glass
350116adecbSSimon Glass        # This should fail since it would need to increase the device-tree size
351fa80c25cSSimon Glass        self.node.AddZeroProp('four')
352116adecbSSimon Glass        with self.assertRaises(libfdt.FdtException) as e:
353fa80c25cSSimon Glass            self.dtb.Sync(auto_resize=False)
354116adecbSSimon Glass        self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
3556434961bSSimon Glass        self.dtb.Sync(auto_resize=True)
356116adecbSSimon Glass
357fa80c25cSSimon Glass    def testAddNode(self):
358fa80c25cSSimon Glass        self.fdt.pack()
359e21c27afSSimon Glass        self.node.AddSubnode('subnode')
360e21c27afSSimon Glass        with self.assertRaises(libfdt.FdtException) as e:
361e21c27afSSimon Glass            self.dtb.Sync(auto_resize=False)
362e21c27afSSimon Glass        self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
363e21c27afSSimon Glass
364e21c27afSSimon Glass        self.dtb.Sync(auto_resize=True)
365e21c27afSSimon Glass        offset = self.fdt.path_offset('/spl-test/subnode')
366e21c27afSSimon Glass        self.assertTrue(offset > 0)
367fa80c25cSSimon Glass
3686434961bSSimon Glass    def testAddMore(self):
3696434961bSSimon Glass        """Test various other methods for adding and setting properties"""
3706434961bSSimon Glass        self.node.AddZeroProp('one')
3716434961bSSimon Glass        self.dtb.Sync(auto_resize=True)
3726434961bSSimon Glass        data = self.fdt.getprop(self.node.Offset(), 'one')
3736434961bSSimon Glass        self.assertEqual(0, fdt32_to_cpu(data))
3746434961bSSimon Glass
3756434961bSSimon Glass        self.node.SetInt('one', 1)
3766434961bSSimon Glass        self.dtb.Sync(auto_resize=False)
3776434961bSSimon Glass        data = self.fdt.getprop(self.node.Offset(), 'one')
3786434961bSSimon Glass        self.assertEqual(1, fdt32_to_cpu(data))
3796434961bSSimon Glass
3806434961bSSimon Glass        val = '123' + chr(0) + '456'
3816434961bSSimon Glass        self.node.AddString('string', val)
3826434961bSSimon Glass        self.dtb.Sync(auto_resize=True)
3836434961bSSimon Glass        data = self.fdt.getprop(self.node.Offset(), 'string')
3846434961bSSimon Glass        self.assertEqual(val + '\0', data)
3856434961bSSimon Glass
3866434961bSSimon Glass        self.fdt.pack()
3876434961bSSimon Glass        self.node.SetString('string', val + 'x')
3886434961bSSimon Glass        with self.assertRaises(libfdt.FdtException) as e:
3896434961bSSimon Glass            self.dtb.Sync(auto_resize=False)
3906434961bSSimon Glass        self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
3916434961bSSimon Glass        self.node.SetString('string', val[:-1])
3926434961bSSimon Glass
3936434961bSSimon Glass        prop = self.node.props['string']
3946434961bSSimon Glass        prop.SetData(val)
3956434961bSSimon Glass        self.dtb.Sync(auto_resize=False)
3966434961bSSimon Glass        data = self.fdt.getprop(self.node.Offset(), 'string')
3976434961bSSimon Glass        self.assertEqual(val, data)
3986434961bSSimon Glass
3996434961bSSimon Glass        self.node.AddEmptyProp('empty', 5)
4006434961bSSimon Glass        self.dtb.Sync(auto_resize=True)
4016434961bSSimon Glass        prop = self.node.props['empty']
4026434961bSSimon Glass        prop.SetData(val)
4036434961bSSimon Glass        self.dtb.Sync(auto_resize=False)
4046434961bSSimon Glass        data = self.fdt.getprop(self.node.Offset(), 'empty')
4056434961bSSimon Glass        self.assertEqual(val, data)
4066434961bSSimon Glass
4076434961bSSimon Glass        self.node.SetData('empty', '123')
4086434961bSSimon Glass        self.assertEqual('123', prop.bytes)
4096434961bSSimon Glass
410746aee3fSSimon Glass    def testFromData(self):
411746aee3fSSimon Glass        dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
412746aee3fSSimon Glass        self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
413746aee3fSSimon Glass
414746aee3fSSimon Glass        self.node.AddEmptyProp('empty', 5)
415746aee3fSSimon Glass        self.dtb.Sync(auto_resize=True)
416746aee3fSSimon Glass        self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
417746aee3fSSimon Glass
4182ba98753SSimon Glass
4192a2d91d0SSimon Glassclass TestFdtUtil(unittest.TestCase):
4202a2d91d0SSimon Glass    """Tests for the fdt_util module
4212a2d91d0SSimon Glass
4222a2d91d0SSimon Glass    This module will likely be mostly replaced at some point, once upstream
4232a2d91d0SSimon Glass    libfdt has better Python support. For now, this provides tests for current
4242a2d91d0SSimon Glass    functionality.
4252a2d91d0SSimon Glass    """
4262a2d91d0SSimon Glass    @classmethod
4272a2d91d0SSimon Glass    def setUpClass(cls):
4282a2d91d0SSimon Glass        tools.PrepareOutputDir(None)
4292a2d91d0SSimon Glass
430e0e6275fSSimon Glass    @classmethod
431e0e6275fSSimon Glass    def tearDownClass(cls):
432e0e6275fSSimon Glass        tools.FinaliseOutputDir()
433e0e6275fSSimon Glass
4342a2d91d0SSimon Glass    def setUp(self):
4352a2d91d0SSimon Glass        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
4362a2d91d0SSimon Glass        self.node = self.dtb.GetNode('/spl-test')
4372a2d91d0SSimon Glass
4382a2d91d0SSimon Glass    def testGetInt(self):
4392a2d91d0SSimon Glass        self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
4402a2d91d0SSimon Glass        self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
4412a2d91d0SSimon Glass
4422a2d91d0SSimon Glass        with self.assertRaises(ValueError) as e:
4432a2d91d0SSimon Glass            self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
4442a2d91d0SSimon Glass        self.assertIn("property 'intarray' has list value: expecting a single "
4452a2d91d0SSimon Glass                      'integer', str(e.exception))
4462a2d91d0SSimon Glass
4472a2d91d0SSimon Glass    def testGetString(self):
4482a2d91d0SSimon Glass        self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
4492a2d91d0SSimon Glass        self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
4502a2d91d0SSimon Glass                                                    'test'))
4512a2d91d0SSimon Glass
4522a2d91d0SSimon Glass        with self.assertRaises(ValueError) as e:
4532a2d91d0SSimon Glass            self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
4542a2d91d0SSimon Glass        self.assertIn("property 'stringarray' has list value: expecting a "
4552a2d91d0SSimon Glass                      'single string', str(e.exception))
4562a2d91d0SSimon Glass
4572a2d91d0SSimon Glass    def testGetBool(self):
4582a2d91d0SSimon Glass        self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
4592a2d91d0SSimon Glass        self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
4602a2d91d0SSimon Glass        self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
4612a2d91d0SSimon Glass        self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
4622a2d91d0SSimon Glass
4633af8e49cSSimon Glass    def testGetByte(self):
4643af8e49cSSimon Glass        self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
4653af8e49cSSimon Glass        self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
4663af8e49cSSimon Glass
4673af8e49cSSimon Glass        with self.assertRaises(ValueError) as e:
4683af8e49cSSimon Glass            fdt_util.GetByte(self.node, 'longbytearray')
4693af8e49cSSimon Glass        self.assertIn("property 'longbytearray' has list value: expecting a "
4703af8e49cSSimon Glass                      'single byte', str(e.exception))
4713af8e49cSSimon Glass
4723af8e49cSSimon Glass        with self.assertRaises(ValueError) as e:
4733af8e49cSSimon Glass            fdt_util.GetByte(self.node, 'intval')
4743af8e49cSSimon Glass        self.assertIn("property 'intval' has length 4, expecting 1",
4753af8e49cSSimon Glass                      str(e.exception))
4763af8e49cSSimon Glass
47794a7c603SSimon Glass    def testGetPhandleList(self):
47894a7c603SSimon Glass        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
47994a7c603SSimon Glass        node = dtb.GetNode('/phandle-source2')
48094a7c603SSimon Glass        self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
48194a7c603SSimon Glass        node = dtb.GetNode('/phandle-source')
48294a7c603SSimon Glass        self.assertEqual([1, 2, 11, 3, 12, 13, 1],
48394a7c603SSimon Glass                         fdt_util.GetPhandleList(node, 'clocks'))
48494a7c603SSimon Glass        self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
48594a7c603SSimon Glass
48653af22a9SSimon Glass    def testGetDataType(self):
48753af22a9SSimon Glass        self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
48853af22a9SSimon Glass        self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
48953af22a9SSimon Glass                                                         str))
49053af22a9SSimon Glass        with self.assertRaises(ValueError) as e:
49153af22a9SSimon Glass            self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
49253af22a9SSimon Glass                                                     bool))
4932a2d91d0SSimon Glass    def testFdtCellsToCpu(self):
4942a2d91d0SSimon Glass        val = self.node.props['intarray'].value
4952a2d91d0SSimon Glass        self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
4962a2d91d0SSimon Glass        self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
4972a2d91d0SSimon Glass
4982a2d91d0SSimon Glass        dtb2 = fdt.FdtScan('tools/dtoc/dtoc_test_addr64.dts')
4992a2d91d0SSimon Glass        node2 = dtb2.GetNode('/test1')
5002a2d91d0SSimon Glass        val = node2.props['reg'].value
5012a2d91d0SSimon Glass        self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
5022a2d91d0SSimon Glass
5032a2d91d0SSimon Glass    def testEnsureCompiled(self):
5042a2d91d0SSimon Glass        """Test a degenerate case of this function"""
5052a2d91d0SSimon Glass        dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
5062a2d91d0SSimon Glass        self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
5072a2d91d0SSimon Glass
5082a2d91d0SSimon Glass    def testGetPlainBytes(self):
5092a2d91d0SSimon Glass        self.assertEqual('fred', fdt_util.get_plain_bytes('fred'))
5102a2d91d0SSimon Glass
5112a2d91d0SSimon Glass
5122a2d91d0SSimon Glassdef RunTestCoverage():
5132a2d91d0SSimon Glass    """Run the tests and check that we get 100% coverage"""
5142a2d91d0SSimon Glass    test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
5152a2d91d0SSimon Glass            ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
5162a2d91d0SSimon Glass
5172a2d91d0SSimon Glass
5182ba98753SSimon Glassdef RunTests(args):
5192ba98753SSimon Glass    """Run all the test we have for the fdt model
5202ba98753SSimon Glass
5212ba98753SSimon Glass    Args:
5222ba98753SSimon Glass        args: List of positional args provided to fdt. This can hold a test
5232ba98753SSimon Glass            name to execute (as in 'fdt -t testFdt', for example)
5242ba98753SSimon Glass    """
5252ba98753SSimon Glass    result = unittest.TestResult()
5262ba98753SSimon Glass    sys.argv = [sys.argv[0]]
5272ba98753SSimon Glass    test_name = args and args[0] or None
5282a2d91d0SSimon Glass    for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
5292ba98753SSimon Glass        if test_name:
5302ba98753SSimon Glass            try:
5312ba98753SSimon Glass                suite = unittest.TestLoader().loadTestsFromName(test_name, module)
5322ba98753SSimon Glass            except AttributeError:
5332ba98753SSimon Glass                continue
5342ba98753SSimon Glass        else:
5352ba98753SSimon Glass            suite = unittest.TestLoader().loadTestsFromTestCase(module)
5362ba98753SSimon Glass        suite.run(result)
5372ba98753SSimon Glass
5382ba98753SSimon Glass    print result
5392ba98753SSimon Glass    for _, err in result.errors:
5402ba98753SSimon Glass        print err
5412ba98753SSimon Glass    for _, err in result.failures:
5422ba98753SSimon Glass        print err
5432ba98753SSimon Glass
5442ba98753SSimon Glassif __name__ != '__main__':
5452ba98753SSimon Glass    sys.exit(1)
5462ba98753SSimon Glass
5472ba98753SSimon Glassparser = OptionParser()
5482a2d91d0SSimon Glassparser.add_option('-B', '--build-dir', type='string', default='b',
5492a2d91d0SSimon Glass        help='Directory containing the build output')
550*11ae93eeSSimon Glassparser.add_option('-P', '--processes', type=int,
551*11ae93eeSSimon Glass                  help='set number of processes to use for running tests')
5522ba98753SSimon Glassparser.add_option('-t', '--test', action='store_true', dest='test',
5532ba98753SSimon Glass                  default=False, help='run tests')
5542a2d91d0SSimon Glassparser.add_option('-T', '--test-coverage', action='store_true',
5552a2d91d0SSimon Glass                default=False, help='run tests and check for 100% coverage')
5562ba98753SSimon Glass(options, args) = parser.parse_args()
5572ba98753SSimon Glass
5582ba98753SSimon Glass# Run our meagre tests
5592ba98753SSimon Glassif options.test:
5602ba98753SSimon Glass    RunTests(args)
5612a2d91d0SSimon Glasselif options.test_coverage:
5622a2d91d0SSimon Glass    RunTestCoverage()
563