-#!/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>
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, 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
data = dtb.GetContents()[offset:offset + len(prop.value)]
return prop, [chr(x) for x in data]
+def find_dtb_file(dts_fname):
+ """Locate a test file in the test/ directory
+
+ Args:
+ dts_fname (str): Filename to find, e.g. 'dtoc_test_simple.dts]
+
+ Returns:
+ str: Path to the test filename
+ """
+ return os.path.join('tools/dtoc/test', dts_fname)
+
class TestFdt(unittest.TestCase):
"""Tests for the Fdt module
@classmethod
def tearDownClass(cls):
- tools._FinaliseForTest()
+ tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
def testFdt(self):
"""Test that we can open an Fdt"""
"""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):
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"""
@classmethod
def tearDownClass(cls):
- tools._FinaliseForTest()
+ tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
+ self.fdt = self.dtb.GetFdtObj()
def testOffset(self):
"""Tests that we can obtain the offset of a node"""
def testRefreshExtraNode(self):
"""Test refreshing offsets when an expected node is missing"""
# Delete it from the device tre, not our tables
- self.dtb.GetFdtObj().del_node(self.node.Offset())
+ self.fdt.del_node(self.node.Offset())
with self.assertRaises(ValueError) as e:
self.dtb.Refresh()
self.assertIn('Internal error, node name mismatch '
del self.node.props['notstring']
with self.assertRaises(ValueError) as e:
self.dtb.Refresh()
- self.assertIn("Internal error, property 'notstring' missing, offset ",
+ self.assertIn("Internal error, node '/spl-test' 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')
+ dtb = fdt.FdtScan(find_dtb_file('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)))
+ def testAddNodeSpace(self):
+ """Test adding a single node when out of space"""
+ 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 testAddNodes(self):
+ """Test adding various subnode and properies"""
+ node = self.dtb.GetNode('/i2c@0')
+
+ # Add one more node next to the pmic one
+ sn1 = node.AddSubnode('node-one')
+ sn1.AddInt('integer-a', 12)
+ sn1.AddInt('integer-b', 23)
+
+ # Sync so that everything is clean
+ self.dtb.Sync(auto_resize=True)
+
+ # Add two subnodes next to pmic and node-one
+ sn2 = node.AddSubnode('node-two')
+ sn2.AddInt('integer-2a', 34)
+ sn2.AddInt('integer-2b', 45)
+
+ sn3 = node.AddSubnode('node-three')
+ sn3.AddInt('integer-3', 123)
+
+ # Add a property to the node after i2c@0 to check that this is not
+ # disturbed by adding a subnode to i2c@0
+ orig_node = self.dtb.GetNode('/orig-node')
+ orig_node.AddInt('integer-4', 456)
+
+ # Add a property to the pmic node to check that pmic properties are not
+ # disturbed
+ pmic = self.dtb.GetNode('/i2c@0/pmic@9')
+ pmic.AddInt('integer-5', 567)
+
+ self.dtb.Sync(auto_resize=True)
+
+ def testRefreshNameMismatch(self):
+ """Test name mismatch when syncing nodes and properties"""
+ prop = self.node.AddInt('integer-a', 12)
+
+ wrong_offset = self.dtb.GetNode('/i2c@0')._offset
+ self.node._offset = wrong_offset
+ with self.assertRaises(ValueError) as e:
+ self.dtb.Sync()
+ self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
+ str(e.exception))
+
+ with self.assertRaises(ValueError) as e:
+ self.node.Refresh(wrong_offset)
+ self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
+ str(e.exception))
+
class TestProp(unittest.TestCase):
"""Test operation of the Prop class"""
@classmethod
def tearDownClass(cls):
- tools._FinaliseForTest()
+ tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
self.fdt = self.dtb.GetFdtObj()
self.assertEqual(None, self.dtb.GetNode('missing'))
def testPhandle(self):
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
node = dtb.GetNode('/phandle-source2')
prop = node.props['clocks']
self.assertTrue(fdt32_to_cpu(prop.value) > 0)
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):
"""Test we can convert all the the types that are supported"""
prop = self._ConvertProp('boolval')
- self.assertEqual(fdt.TYPE_BOOL, prop.type)
+ self.assertEqual(Type.BOOL, prop.type)
self.assertEqual(True, prop.value)
prop = self._ConvertProp('intval')
- self.assertEqual(fdt.TYPE_INT, prop.type)
+ self.assertEqual(Type.INT, prop.type)
self.assertEqual(1, fdt32_to_cpu(prop.value))
prop = self._ConvertProp('intarray')
- self.assertEqual(fdt.TYPE_INT, prop.type)
+ self.assertEqual(Type.INT, prop.type)
val = [fdt32_to_cpu(val) for val in prop.value]
self.assertEqual([2, 3, 4], val)
prop = self._ConvertProp('byteval')
- self.assertEqual(fdt.TYPE_BYTE, prop.type)
+ self.assertEqual(Type.BYTE, prop.type)
self.assertEqual(5, ord(prop.value))
prop = self._ConvertProp('longbytearray')
- self.assertEqual(fdt.TYPE_BYTE, prop.type)
+ self.assertEqual(Type.BYTE, prop.type)
val = [ord(val) for val in prop.value]
self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
prop = self._ConvertProp('stringval')
- self.assertEqual(fdt.TYPE_STRING, prop.type)
+ self.assertEqual(Type.STRING, prop.type)
self.assertEqual('message', prop.value)
prop = self._ConvertProp('stringarray')
- self.assertEqual(fdt.TYPE_STRING, prop.type)
+ self.assertEqual(Type.STRING, prop.type)
self.assertEqual(['multi-word', 'message'], prop.value)
prop = self._ConvertProp('notstring')
- self.assertEqual(fdt.TYPE_BYTE, prop.type)
+ self.assertEqual(Type.BYTE, prop.type)
val = [ord(val) for val in prop.value]
self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
def testGetEmpty(self):
"""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('', fdt.Prop.GetEmpty(fdt.TYPE_STRING))
+ self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
+ self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
+ self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
+ self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
def testGetOffset(self):
"""Test we can get the offset of a property"""
def testWiden(self):
"""Test widening of values"""
node2 = self.dtb.GetNode('/spl-test2')
+ node3 = self.dtb.GetNode('/spl-test3')
prop = self.node.props['intval']
# No action
prop2 = node2.props['intval']
prop.Widen(prop2)
- self.assertEqual(fdt.TYPE_INT, prop.type)
+ self.assertEqual(Type.INT, prop.type)
self.assertEqual(1, fdt32_to_cpu(prop.value))
# Convert singla value to array
prop2 = self.node.props['intarray']
prop.Widen(prop2)
- self.assertEqual(fdt.TYPE_INT, prop.type)
+ self.assertEqual(Type.INT, prop.type)
self.assertTrue(isinstance(prop.value, list))
# A 4-byte array looks like a single integer. When widened by a longer
# byte array, it should turn into an array.
prop = self.node.props['longbytearray']
prop2 = node2.props['longbytearray']
+ prop3 = node3.props['longbytearray']
self.assertFalse(isinstance(prop2.value, list))
self.assertEqual(4, len(prop2.value))
+ self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
prop2.Widen(prop)
self.assertTrue(isinstance(prop2.value, list))
self.assertEqual(9, len(prop2.value))
+ self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
+ '\0', '\0', '\0', '\0'], prop2.value)
+ prop3.Widen(prop)
+ self.assertTrue(isinstance(prop3.value, list))
+ self.assertEqual(9, len(prop3.value))
+ self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
+ '\x0e', '\x0f', '\x10', '\0'], prop3.value)
# Similarly for a string array
prop = self.node.props['stringval']
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.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.node.SetInt('four', 4)
+ self.dtb.Sync(auto_resize=False)
self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
+ self.dtb.Sync(auto_resize=True)
+
+ 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 = 1234
+ self.node.AddInt('integer', val)
+ self.dtb.Sync(auto_resize=True)
+ data = self.fdt.getprop(self.node.Offset(), 'integer')
+ self.assertEqual(val, 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)
+
+ # Trying adding a lot of data at once
+ self.node.AddData('data', tools.GetBytes(65, 20000))
+ self.dtb.Sync(auto_resize=True)
+
+ 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):
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.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
def testGetInt(self):
str(e.exception))
def testGetPhandleList(self):
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
node = dtb.GetNode('/phandle-source2')
self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
node = dtb.GetNode('/phandle-source')
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
+ dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
+ 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"""
- dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
+ """Test a degenerate case of this function (file already compiled)"""
+ dtb = fdt_util.EnsureCompiled(find_dtb_file('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(find_dtb_file('dtoc_test_simple.dts'),
+ tmpdir)
+ self.assertEqual(tmpdir, os.path.dirname(dtb))
+ shutil.rmtree(tmpdir)
+ finally:
+ tools.outdir= old_outdir
def RunTestCoverage():
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)
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',