Browse Source

dtoc: Update fdt tests to increase code coverage

At present only some of the fdt functionality is tested. Add more tests to
cover the rest of it. Also turn on test coverage, which is now 100% with
a small exclusion for a Python 3 feature.

Signed-off-by: Simon Glass <sjg@chromium.org>
Simon Glass 6 years ago
parent
commit
2a2d91d0d6
5 changed files with 150 additions and 24 deletions
  1. 1 0
      tools/dtoc/dtoc_test_simple.dts
  2. 0 12
      tools/dtoc/fdt.py
  3. 16 9
      tools/dtoc/fdt_util.py
  4. 2 0
      tools/dtoc/test_dtoc.py
  5. 131 3
      tools/dtoc/test_fdt.py

+ 1 - 0
tools/dtoc/dtoc_test_simple.dts

@@ -21,6 +21,7 @@
 		longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11];
 		longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11];
 		stringval = "message";
 		stringval = "message";
 		stringarray = "multi-word", "message";
 		stringarray = "multi-word", "message";
+		notstring = [20 21 22 10 00];
 	};
 	};
 
 
 	spl-test2 {
 	spl-test2 {

+ 0 - 12
tools/dtoc/fdt.py

@@ -49,13 +49,6 @@ class Prop:
             return
             return
         self.type, self.value = self.BytesToValue(bytes)
         self.type, self.value = self.BytesToValue(bytes)
 
 
-    def GetPhandle(self):
-        """Get a (single) phandle value from a property
-
-        Gets the phandle valuie from a property and returns it as an integer
-        """
-        return fdt_util.fdt32_to_cpu(self.value[:4])
-
     def Widen(self, newprop):
     def Widen(self, newprop):
         """Figure out which property type is more general
         """Figure out which property type is more general
 
 
@@ -344,11 +337,6 @@ class Fdt:
         """
         """
         return self._fdt_obj
         return self._fdt_obj
 
 
-    def CheckErr(self, errnum, msg):
-        if errnum:
-            raise ValueError('Error %d: %s: %s' %
-                (errnum, libfdt.fdt_strerror(errnum), msg))
-
     def GetProps(self, node):
     def GetProps(self, node):
         """Get all properties from a node.
         """Get all properties from a node.
 
 

+ 16 - 9
tools/dtoc/fdt_util.py

@@ -13,6 +13,14 @@ import tempfile
 import command
 import command
 import tools
 import tools
 
 
+VERSION3 = sys.version_info > (3, 0)
+
+def get_plain_bytes(val):
+    """Handle Python 3 strings"""
+    if isinstance(val, bytes):
+        val = val.decode('utf-8')
+    return val.encode('raw_unicode_escape')
+
 def fdt32_to_cpu(val):
 def fdt32_to_cpu(val):
     """Convert a device tree cell to an integer
     """Convert a device tree cell to an integer
 
 
@@ -22,10 +30,9 @@ def fdt32_to_cpu(val):
     Return:
     Return:
         A native-endian integer value
         A native-endian integer value
     """
     """
-    if sys.version_info > (3, 0):
-        if isinstance(val, bytes):
-            val = val.decode('utf-8')
-        val = val.encode('raw_unicode_escape')
+    if VERSION3:
+        # This code is not reached in Python 2
+        val = get_plain_bytes(val)  # pragma: no cover
     return struct.unpack('>I', val)[0]
     return struct.unpack('>I', val)[0]
 
 
 def fdt_cells_to_cpu(val, cells):
 def fdt_cells_to_cpu(val, cells):
@@ -86,10 +93,10 @@ def GetInt(node, propname, default=None):
     prop = node.props.get(propname)
     prop = node.props.get(propname)
     if not prop:
     if not prop:
         return default
         return default
-    value = fdt32_to_cpu(prop.value)
-    if type(value) == type(list):
-        raise ValueError("Node '%s' property '%' has list value: expecting"
+    if isinstance(prop.value, list):
+        raise ValueError("Node '%s' property '%s' has list value: expecting "
                          "a single integer" % (node.name, propname))
                          "a single integer" % (node.name, propname))
+    value = fdt32_to_cpu(prop.value)
     return value
     return value
 
 
 def GetString(node, propname, default=None):
 def GetString(node, propname, default=None):
@@ -97,8 +104,8 @@ def GetString(node, propname, default=None):
     if not prop:
     if not prop:
         return default
         return default
     value = prop.value
     value = prop.value
-    if type(value) == type(list):
-        raise ValueError("Node '%s' property '%' has list value: expecting"
+    if isinstance(value, list):
+        raise ValueError("Node '%s' property '%s' has list value: expecting "
                          "a single string" % (node.name, propname))
                          "a single string" % (node.name, propname))
     return value
     return value
 
 

+ 2 - 0
tools/dtoc/test_dtoc.py

@@ -180,6 +180,7 @@ struct dtd_sandbox_spl_test {
 \tfdt32_t\t\tintarray[4];
 \tfdt32_t\t\tintarray[4];
 \tfdt32_t\t\tintval;
 \tfdt32_t\t\tintval;
 \tunsigned char\tlongbytearray[9];
 \tunsigned char\tlongbytearray[9];
+\tunsigned char\tnotstring[5];
 \tconst char *\tstringarray[3];
 \tconst char *\tstringarray[3];
 \tconst char *\tstringval;
 \tconst char *\tstringval;
 };
 };
@@ -195,6 +196,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
 \t.bytearray\t\t= {0x6, 0x0, 0x0},
 \t.bytearray\t\t= {0x6, 0x0, 0x0},
 \t.byteval\t\t= 0x5,
 \t.byteval\t\t= 0x5,
 \t.intval\t\t\t= 0x1,
 \t.intval\t\t\t= 0x1,
+\t.notstring\t\t= {0x20, 0x21, 0x22, 0x10, 0x0},
 \t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
 \t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
 \t\t0x11},
 \t\t0x11},
 \t.stringval\t\t= "message",
 \t.stringval\t\t= "message",

+ 131 - 3
tools/dtoc/test_fdt.py

@@ -18,6 +18,7 @@ for dirname in ['../patman', '..']:
 import command
 import command
 import fdt
 import fdt
 from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL
 from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL
+import fdt_util
 from fdt_util import fdt32_to_cpu
 from fdt_util import fdt32_to_cpu
 import libfdt
 import libfdt
 import test_util
 import test_util
@@ -53,6 +54,7 @@ class TestFdt(unittest.TestCase):
         node = self.dtb.GetNode('/i2c@0/pmic@9')
         node = self.dtb.GetNode('/i2c@0/pmic@9')
         self.assertTrue(isinstance(node, fdt.Node))
         self.assertTrue(isinstance(node, fdt.Node))
         self.assertEqual('pmic@9', node.name)
         self.assertEqual('pmic@9', node.name)
+        self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
 
 
     def testFlush(self):
     def testFlush(self):
         """Check that we can flush the device tree out to its file"""
         """Check that we can flush the device tree out to its file"""
@@ -79,14 +81,14 @@ class TestFdt(unittest.TestCase):
         node = self.dtb.GetNode('/spl-test')
         node = self.dtb.GetNode('/spl-test')
         props = self.dtb.GetProps(node)
         props = self.dtb.GetProps(node)
         self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
         self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
-                          'intarray', 'intval', 'longbytearray',
+                          'intarray', 'intval', 'longbytearray', 'notstring',
                           'stringarray', 'stringval', 'u-boot,dm-pre-reloc'],
                           'stringarray', 'stringval', 'u-boot,dm-pre-reloc'],
                          sorted(props.keys()))
                          sorted(props.keys()))
 
 
     def testCheckError(self):
     def testCheckError(self):
         """Tests the ChecKError() function"""
         """Tests the ChecKError() function"""
         with self.assertRaises(ValueError) as e:
         with self.assertRaises(ValueError) as e:
-            self.dtb.CheckErr(-libfdt.NOTFOUND, 'hello')
+            fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
         self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
         self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
 
 
 
 
@@ -119,6 +121,8 @@ class TestNode(unittest.TestCase):
         self.node.DeleteProp('intarray')
         self.node.DeleteProp('intarray')
         offset3 = node2.Offset()
         offset3 = node2.Offset()
         self.assertTrue(offset3 < offset2)
         self.assertTrue(offset3 < offset2)
+        with self.assertRaises(libfdt.FdtException):
+            self.node.DeleteProp('missing')
 
 
     def testFindNode(self):
     def testFindNode(self):
         """Tests that we can find a node using the _FindNode() functoin"""
         """Tests that we can find a node using the _FindNode() functoin"""
@@ -126,6 +130,7 @@ class TestNode(unittest.TestCase):
         self.assertEqual('i2c@0', node.name)
         self.assertEqual('i2c@0', node.name)
         subnode = node._FindNode('pmic@9')
         subnode = node._FindNode('pmic@9')
         self.assertEqual('pmic@9', subnode.name)
         self.assertEqual('pmic@9', subnode.name)
+        self.assertEqual(None, node._FindNode('missing'))
 
 
 
 
 class TestProp(unittest.TestCase):
 class TestProp(unittest.TestCase):
@@ -144,6 +149,58 @@ class TestProp(unittest.TestCase):
         self.node = self.dtb.GetNode('/spl-test')
         self.node = self.dtb.GetNode('/spl-test')
         self.fdt = self.dtb.GetFdtObj()
         self.fdt = self.dtb.GetFdtObj()
 
 
+    def testPhandle(self):
+        dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+        node = dtb.GetNode('/phandle-source')
+
+    def _ConvertProp(self, prop_name):
+        """Helper function to look up a property in self.node and return it
+
+        Args:
+            Property name to find
+
+        Return fdt.Prop object for this property
+        """
+        p = self.fdt.get_property(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(True, prop.value)
+
+        prop = self._ConvertProp('intval')
+        self.assertEqual(fdt.TYPE_INT, prop.type)
+        self.assertEqual(1, fdt32_to_cpu(prop.value))
+
+        prop = self._ConvertProp('intarray')
+        self.assertEqual(fdt.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(5, ord(prop.value))
+
+        prop = self._ConvertProp('longbytearray')
+        self.assertEqual(fdt.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('message', prop.value)
+
+        prop = self._ConvertProp('stringarray')
+        self.assertEqual(fdt.TYPE_STRING, prop.type)
+        self.assertEqual(['multi-word', 'message'], prop.value)
+
+        prop = self._ConvertProp('notstring')
+        self.assertEqual(fdt.TYPE_BYTE, prop.type)
+        val = [ord(val) for val in prop.value]
+        self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
+
     def testGetEmpty(self):
     def testGetEmpty(self):
         """Tests the GetEmpty() function for the various supported types"""
         """Tests the GetEmpty() function for the various supported types"""
         self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL))
         self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL))
@@ -207,6 +264,71 @@ class TestProp(unittest.TestCase):
         self.assertEqual(3, len(prop.value))
         self.assertEqual(3, len(prop.value))
 
 
 
 
+class TestFdtUtil(unittest.TestCase):
+    """Tests for the fdt_util module
+
+    This module will likely be mostly replaced at some point, once upstream
+    libfdt has better Python support. For now, this provides tests for current
+    functionality.
+    """
+    @classmethod
+    def setUpClass(cls):
+        tools.PrepareOutputDir(None)
+
+    def setUp(self):
+        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+        self.node = self.dtb.GetNode('/spl-test')
+
+    def testGetInt(self):
+        self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
+        self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
+
+        with self.assertRaises(ValueError) as e:
+            self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
+        self.assertIn("property 'intarray' has list value: expecting a single "
+                      'integer', str(e.exception))
+
+    def testGetString(self):
+        self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
+        self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
+                                                    'test'))
+
+        with self.assertRaises(ValueError) as e:
+            self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
+        self.assertIn("property 'stringarray' has list value: expecting a "
+                      'single string', str(e.exception))
+
+    def testGetBool(self):
+        self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
+        self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
+        self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
+        self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
+
+    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
+        self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
+
+    def testEnsureCompiled(self):
+        """Test a degenerate case of this function"""
+        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 RunTestCoverage():
+    """Run the tests and check that we get 100% coverage"""
+    test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
+            ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
+
+
 def RunTests(args):
 def RunTests(args):
     """Run all the test we have for the fdt model
     """Run all the test we have for the fdt model
 
 
@@ -217,7 +339,7 @@ def RunTests(args):
     result = unittest.TestResult()
     result = unittest.TestResult()
     sys.argv = [sys.argv[0]]
     sys.argv = [sys.argv[0]]
     test_name = args and args[0] or None
     test_name = args and args[0] or None
-    for module in (TestFdt, TestNode, TestProp):
+    for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
         if test_name:
         if test_name:
             try:
             try:
                 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
                 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
@@ -237,10 +359,16 @@ if __name__ != '__main__':
     sys.exit(1)
     sys.exit(1)
 
 
 parser = OptionParser()
 parser = OptionParser()
+parser.add_option('-B', '--build-dir', type='string', default='b',
+        help='Directory containing the build output')
 parser.add_option('-t', '--test', action='store_true', dest='test',
 parser.add_option('-t', '--test', action='store_true', dest='test',
                   default=False, help='run tests')
                   default=False, help='run tests')
+parser.add_option('-T', '--test-coverage', action='store_true',
+                default=False, help='run tests and check for 100% coverage')
 (options, args) = parser.parse_args()
 (options, args) = parser.parse_args()
 
 
 # Run our meagre tests
 # Run our meagre tests
 if options.test:
 if options.test:
     RunTests(args)
     RunTests(args)
+elif options.test_coverage:
+    RunTestCoverage()