Merge tag 'u-boot-rockchip-20200501' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / tools / dtoc / test_fdt.py
index 9fef8ed..375e906 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0+
 # Copyright (c) 2018 Google, Inc
 # Written by Simon Glass <sjg@chromium.org>
@@ -7,22 +7,23 @@
 from optparse import OptionParser
 import glob
 import os
+import shutil
 import sys
+import tempfile
 import unittest
 
 # Bring in the patman libraries
 our_path = os.path.dirname(os.path.realpath(__file__))
-for dirname in ['../patman', '..']:
-    sys.path.insert(0, os.path.join(our_path, dirname))
-
-import command
-import fdt
-from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL
-import fdt_util
-from fdt_util import fdt32_to_cpu
+sys.path.insert(1, os.path.join(our_path, '..'))
+
+from dtoc import fdt
+from dtoc import fdt_util
+from dtoc.fdt_util import fdt32_to_cpu
+from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, BytesToValue
 import libfdt
-import test_util
-import tools
+from patman import command
+from patman import test_util
+from patman import tools
 
 def _GetPropertyValue(dtb, node, prop_name):
     """Low-level function to get the property value based on its offset
@@ -45,7 +46,7 @@ def _GetPropertyValue(dtb, node, prop_name):
     # Add 12, which is sizeof(struct fdt_property), to get to start of data
     offset = prop.GetOffset() + 12
     data = dtb.GetContents()[offset:offset + len(prop.value)]
-    return prop, [chr(x) for x in data]
+    return prop, [tools.ToChar(x) for x in data]
 
 
 class TestFdt(unittest.TestCase):
@@ -60,7 +61,7 @@ class TestFdt(unittest.TestCase):
 
     @classmethod
     def tearDownClass(cls):
-        tools._FinaliseForTest()
+        tools.FinaliseOutputDir()
 
     def setUp(self):
         self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
@@ -75,21 +76,26 @@ class TestFdt(unittest.TestCase):
         """Test the GetNode() method"""
         node = self.dtb.GetNode('/spl-test')
         self.assertTrue(isinstance(node, fdt.Node))
+
         node = self.dtb.GetNode('/i2c@0/pmic@9')
         self.assertTrue(isinstance(node, fdt.Node))
         self.assertEqual('pmic@9', node.name)
         self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
 
+        node = self.dtb.GetNode('/')
+        self.assertTrue(isinstance(node, fdt.Node))
+        self.assertEqual(0, node.Offset())
+
     def testFlush(self):
         """Check that we can flush the device tree out to its file"""
         fname = self.dtb._fname
-        with open(fname) as fd:
+        with open(fname, 'rb') as fd:
             data = fd.read()
         os.remove(fname)
         with self.assertRaises(IOError):
-            open(fname)
+            open(fname, 'rb')
         self.dtb.Flush()
-        with open(fname) as fd:
+        with open(fname, 'rb') as fd:
             data = fd.read()
 
     def testPack(self):
@@ -115,6 +121,13 @@ class TestFdt(unittest.TestCase):
             fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
         self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
 
+    def testGetFdt(self):
+        node = self.dtb.GetNode('/spl-test')
+        self.assertEqual(self.dtb, node.GetFdt())
+
+    def testBytesToValue(self):
+        self.assertEqual(BytesToValue(b'this\0is\0'),
+                         (TYPE_STRING, ['this', 'is']))
 
 class TestNode(unittest.TestCase):
     """Test operation of the Node class"""
@@ -125,7 +138,7 @@ class TestNode(unittest.TestCase):
 
     @classmethod
     def tearDownClass(cls):
-        tools._FinaliseForTest()
+        tools.FinaliseOutputDir()
 
     def setUp(self):
         self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
@@ -155,12 +168,12 @@ class TestNode(unittest.TestCase):
         self.assertEqual(prop.value, value)
 
     def testFindNode(self):
-        """Tests that we can find a node using the _FindNode() functoin"""
-        node = self.dtb.GetRoot()._FindNode('i2c@0')
+        """Tests that we can find a node using the FindNode() functoin"""
+        node = self.dtb.GetRoot().FindNode('i2c@0')
         self.assertEqual('i2c@0', node.name)
-        subnode = node._FindNode('pmic@9')
+        subnode = node.FindNode('pmic@9')
         self.assertEqual('pmic@9', subnode.name)
-        self.assertEqual(None, node._FindNode('missing'))
+        self.assertEqual(None, node.FindNode('missing'))
 
     def testRefreshMissingNode(self):
         """Test refreshing offsets when an extra node is present in dtb"""
@@ -188,6 +201,14 @@ class TestNode(unittest.TestCase):
         self.assertIn("Internal error, property 'notstring' missing, offset ",
                       str(e.exception))
 
+    def testLookupPhandle(self):
+        """Test looking up a single phandle"""
+        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+        node = dtb.GetNode('/phandle-source2')
+        prop = node.props['clocks']
+        target = dtb.GetNode('/phandle-target')
+        self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
+
 
 class TestProp(unittest.TestCase):
     """Test operation of the Prop class"""
@@ -198,7 +219,7 @@ class TestProp(unittest.TestCase):
 
     @classmethod
     def tearDownClass(cls):
-        tools._FinaliseForTest()
+        tools.FinaliseOutputDir()
 
     def setUp(self):
         self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
@@ -210,7 +231,9 @@ class TestProp(unittest.TestCase):
 
     def testPhandle(self):
         dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
-        node = dtb.GetNode('/phandle-source')
+        node = dtb.GetNode('/phandle-source2')
+        prop = node.props['clocks']
+        self.assertTrue(fdt32_to_cpu(prop.value) > 0)
 
     def _ConvertProp(self, prop_name):
         """Helper function to look up a property in self.node and return it
@@ -220,7 +243,7 @@ class TestProp(unittest.TestCase):
 
         Return fdt.Prop object for this property
         """
-        p = self.fdt.get_property(self.node.Offset(), prop_name)
+        p = self.fdt.getprop(self.node.Offset(), prop_name)
         return fdt.Prop(self.node, -1, prop_name, p)
 
     def testMakeProp(self):
@@ -264,7 +287,7 @@ class TestProp(unittest.TestCase):
         """Tests the GetEmpty() function for the various supported types"""
         self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL))
         self.assertEqual(chr(0), fdt.Prop.GetEmpty(fdt.TYPE_BYTE))
-        self.assertEqual(chr(0) * 4, fdt.Prop.GetEmpty(fdt.TYPE_INT))
+        self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(fdt.TYPE_INT))
         self.assertEqual('', fdt.Prop.GetEmpty(fdt.TYPE_STRING))
 
     def testGetOffset(self):
@@ -317,6 +340,117 @@ class TestProp(unittest.TestCase):
         self.assertTrue(isinstance(prop.value, list))
         self.assertEqual(3, len(prop.value))
 
+    def testAdd(self):
+        """Test adding properties"""
+        self.fdt.pack()
+        # This function should automatically expand the device tree
+        self.node.AddZeroProp('one')
+        self.node.AddZeroProp('two')
+        self.node.AddZeroProp('three')
+        self.dtb.Sync(auto_resize=True)
+
+        # Updating existing properties should be OK, since the device-tree size
+        # does not change
+        self.fdt.pack()
+        self.node.SetInt('one', 1)
+        self.node.SetInt('two', 2)
+        self.node.SetInt('three', 3)
+        self.dtb.Sync(auto_resize=False)
+
+        # This should fail since it would need to increase the device-tree size
+        self.node.AddZeroProp('four')
+        with self.assertRaises(libfdt.FdtException) as e:
+            self.dtb.Sync(auto_resize=False)
+        self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
+        self.dtb.Sync(auto_resize=True)
+
+    def testAddNode(self):
+        self.fdt.pack()
+        self.node.AddSubnode('subnode')
+        with self.assertRaises(libfdt.FdtException) as e:
+            self.dtb.Sync(auto_resize=False)
+        self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
+
+        self.dtb.Sync(auto_resize=True)
+        offset = self.fdt.path_offset('/spl-test/subnode')
+        self.assertTrue(offset > 0)
+
+    def testAddMore(self):
+        """Test various other methods for adding and setting properties"""
+        self.node.AddZeroProp('one')
+        self.dtb.Sync(auto_resize=True)
+        data = self.fdt.getprop(self.node.Offset(), 'one')
+        self.assertEqual(0, fdt32_to_cpu(data))
+
+        self.node.SetInt('one', 1)
+        self.dtb.Sync(auto_resize=False)
+        data = self.fdt.getprop(self.node.Offset(), 'one')
+        self.assertEqual(1, fdt32_to_cpu(data))
+
+        val = '123' + chr(0) + '456'
+        self.node.AddString('string', val)
+        self.dtb.Sync(auto_resize=True)
+        data = self.fdt.getprop(self.node.Offset(), 'string')
+        self.assertEqual(tools.ToBytes(val) + b'\0', data)
+
+        self.fdt.pack()
+        self.node.SetString('string', val + 'x')
+        with self.assertRaises(libfdt.FdtException) as e:
+            self.dtb.Sync(auto_resize=False)
+        self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
+        self.node.SetString('string', val[:-1])
+
+        prop = self.node.props['string']
+        prop.SetData(tools.ToBytes(val))
+        self.dtb.Sync(auto_resize=False)
+        data = self.fdt.getprop(self.node.Offset(), 'string')
+        self.assertEqual(tools.ToBytes(val), data)
+
+        self.node.AddEmptyProp('empty', 5)
+        self.dtb.Sync(auto_resize=True)
+        prop = self.node.props['empty']
+        prop.SetData(tools.ToBytes(val))
+        self.dtb.Sync(auto_resize=False)
+        data = self.fdt.getprop(self.node.Offset(), 'empty')
+        self.assertEqual(tools.ToBytes(val), data)
+
+        self.node.SetData('empty', b'123')
+        self.assertEqual(b'123', prop.bytes)
+
+    def testFromData(self):
+        dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
+        self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
+
+        self.node.AddEmptyProp('empty', 5)
+        self.dtb.Sync(auto_resize=True)
+        self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
+
+    def testMissingSetInt(self):
+        """Test handling of a missing property with SetInt"""
+        with self.assertRaises(ValueError) as e:
+            self.node.SetInt('one', 1)
+        self.assertIn("node '/spl-test': Missing property 'one'",
+                      str(e.exception))
+
+    def testMissingSetData(self):
+        """Test handling of a missing property with SetData"""
+        with self.assertRaises(ValueError) as e:
+            self.node.SetData('one', b'data')
+        self.assertIn("node '/spl-test': Missing property 'one'",
+                      str(e.exception))
+
+    def testMissingSetString(self):
+        """Test handling of a missing property with SetString"""
+        with self.assertRaises(ValueError) as e:
+            self.node.SetString('one', 1)
+        self.assertIn("node '/spl-test': Missing property 'one'",
+                      str(e.exception))
+
+    def testGetFilename(self):
+        """Test the dtb filename can be provided"""
+        self.assertEqual(tools.GetOutputFilename('source.dtb'),
+                         self.dtb.GetFilename())
+
 
 class TestFdtUtil(unittest.TestCase):
     """Tests for the fdt_util module
@@ -329,6 +463,10 @@ class TestFdtUtil(unittest.TestCase):
     def setUpClass(cls):
         tools.PrepareOutputDir(None)
 
+    @classmethod
+    def tearDownClass(cls):
+        tools.FinaliseOutputDir()
+
     def setUp(self):
         self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
         self.node = self.dtb.GetNode('/spl-test')
@@ -358,23 +496,70 @@ class TestFdtUtil(unittest.TestCase):
         self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
         self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
 
+    def testGetByte(self):
+        self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
+        self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
+
+        with self.assertRaises(ValueError) as e:
+            fdt_util.GetByte(self.node, 'longbytearray')
+        self.assertIn("property 'longbytearray' has list value: expecting a "
+                      'single byte', str(e.exception))
+
+        with self.assertRaises(ValueError) as e:
+            fdt_util.GetByte(self.node, 'intval')
+        self.assertIn("property 'intval' has length 4, expecting 1",
+                      str(e.exception))
+
+    def testGetPhandleList(self):
+        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+        node = dtb.GetNode('/phandle-source2')
+        self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
+        node = dtb.GetNode('/phandle-source')
+        self.assertEqual([1, 2, 11, 3, 12, 13, 1],
+                         fdt_util.GetPhandleList(node, 'clocks'))
+        self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
+
+    def testGetDataType(self):
+        self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
+        self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
+                                                         str))
+        with self.assertRaises(ValueError) as e:
+            self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
+                                                     bool))
     def testFdtCellsToCpu(self):
         val = self.node.props['intarray'].value
         self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
         self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
 
         dtb2 = fdt.FdtScan('tools/dtoc/dtoc_test_addr64.dts')
-        node2 = dtb2.GetNode('/test1')
-        val = node2.props['reg'].value
+        node1 = dtb2.GetNode('/test1')
+        val = node1.props['reg'].value
         self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
 
+        node2 = dtb2.GetNode('/test2')
+        val = node2.props['reg'].value
+        self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
+        self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
+                                                                       2))
+        self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
+
     def testEnsureCompiled(self):
-        """Test a degenerate case of this function"""
+        """Test a degenerate case of this function (file already compiled)"""
         dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
         self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
 
-    def testGetPlainBytes(self):
-        self.assertEqual('fred', fdt_util.get_plain_bytes('fred'))
+    def testEnsureCompiledTmpdir(self):
+        """Test providing a temporary directory"""
+        try:
+            old_outdir = tools.outdir
+            tools.outdir= None
+            tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
+            dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts',
+                                          tmpdir)
+            self.assertEqual(tmpdir, os.path.dirname(dtb))
+            shutil.rmtree(tmpdir)
+        finally:
+            tools.outdir= old_outdir
 
 
 def RunTestCoverage():
@@ -403,11 +588,11 @@ def RunTests(args):
             suite = unittest.TestLoader().loadTestsFromTestCase(module)
         suite.run(result)
 
-    print result
+    print(result)
     for _, err in result.errors:
-        print err
+        print(err)
     for _, err in result.failures:
-        print err
+        print(err)
 
 if __name__ != '__main__':
     sys.exit(1)
@@ -415,6 +600,8 @@ if __name__ != '__main__':
 parser = OptionParser()
 parser.add_option('-B', '--build-dir', type='string', default='b',
         help='Directory containing the build output')
+parser.add_option('-P', '--processes', type=int,
+                  help='set number of processes to use for running tests')
 parser.add_option('-t', '--test', action='store_true', dest='test',
                   default=False, help='run tests')
 parser.add_option('-T', '--test-coverage', action='store_true',