xref: /openbmc/u-boot/tools/dtoc/test_fdt.py (revision 2ba98753)
1#!/usr/bin/python
2# SPDX-License-Identifier: GPL-2.0+
3# Copyright (c) 2018 Google, Inc
4# Written by Simon Glass <sjg@chromium.org>
5#
6
7from optparse import OptionParser
8import glob
9import os
10import sys
11import unittest
12
13# Bring in the patman libraries
14our_path = os.path.dirname(os.path.realpath(__file__))
15for dirname in ['../patman', '..']:
16    sys.path.insert(0, os.path.join(our_path, dirname))
17
18import command
19import fdt
20from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL
21from fdt_util import fdt32_to_cpu
22import libfdt
23import test_util
24import tools
25
26class TestFdt(unittest.TestCase):
27    """Tests for the Fdt module
28
29    This includes unit tests for some functions and functional tests for the fdt
30    module.
31    """
32    @classmethod
33    def setUpClass(cls):
34        tools.PrepareOutputDir(None)
35
36    @classmethod
37    def tearDownClass(cls):
38        tools._FinaliseForTest()
39
40    def setUp(self):
41        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
42
43    def testFdt(self):
44        """Test that we can open an Fdt"""
45        self.dtb.Scan()
46        root = self.dtb.GetRoot()
47        self.assertTrue(isinstance(root, fdt.Node))
48
49    def testGetNode(self):
50        """Test the GetNode() method"""
51        node = self.dtb.GetNode('/spl-test')
52        self.assertTrue(isinstance(node, fdt.Node))
53        node = self.dtb.GetNode('/i2c@0/pmic@9')
54        self.assertTrue(isinstance(node, fdt.Node))
55        self.assertEqual('pmic@9', node.name)
56
57    def testFlush(self):
58        """Check that we can flush the device tree out to its file"""
59        fname = self.dtb._fname
60        with open(fname) as fd:
61            data = fd.read()
62        os.remove(fname)
63        with self.assertRaises(IOError):
64            open(fname)
65        self.dtb.Flush()
66        with open(fname) as fd:
67            data = fd.read()
68
69    def testPack(self):
70        """Test that packing a device tree works"""
71        self.dtb.Pack()
72
73    def testGetFdt(self):
74        """Tetst that we can access the raw device-tree data"""
75        self.assertTrue(isinstance(self.dtb.GetFdt(), bytearray))
76
77    def testGetProps(self):
78        """Tests obtaining a list of properties"""
79        node = self.dtb.GetNode('/spl-test')
80        props = self.dtb.GetProps(node)
81        self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
82                          'intarray', 'intval', 'longbytearray',
83                          'stringarray', 'stringval', 'u-boot,dm-pre-reloc'],
84                         sorted(props.keys()))
85
86    def testCheckError(self):
87        """Tests the ChecKError() function"""
88        with self.assertRaises(ValueError) as e:
89            self.dtb.CheckErr(-libfdt.NOTFOUND, 'hello')
90        self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
91
92
93class TestNode(unittest.TestCase):
94    """Test operation of the Node class"""
95
96    @classmethod
97    def setUpClass(cls):
98        tools.PrepareOutputDir(None)
99
100    @classmethod
101    def tearDownClass(cls):
102        tools._FinaliseForTest()
103
104    def setUp(self):
105        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
106        self.node = self.dtb.GetNode('/spl-test')
107
108    def testOffset(self):
109        """Tests that we can obtain the offset of a node"""
110        self.assertTrue(self.node.Offset() > 0)
111
112    def testDelete(self):
113        """Tests that we can delete a property"""
114        node2 = self.dtb.GetNode('/spl-test2')
115        offset1 = node2.Offset()
116        self.node.DeleteProp('intval')
117        offset2 = node2.Offset()
118        self.assertTrue(offset2 < offset1)
119        self.node.DeleteProp('intarray')
120        offset3 = node2.Offset()
121        self.assertTrue(offset3 < offset2)
122
123    def testFindNode(self):
124        """Tests that we can find a node using the _FindNode() functoin"""
125        node = self.dtb.GetRoot()._FindNode('i2c@0')
126        self.assertEqual('i2c@0', node.name)
127        subnode = node._FindNode('pmic@9')
128        self.assertEqual('pmic@9', subnode.name)
129
130
131class TestProp(unittest.TestCase):
132    """Test operation of the Prop class"""
133
134    @classmethod
135    def setUpClass(cls):
136        tools.PrepareOutputDir(None)
137
138    @classmethod
139    def tearDownClass(cls):
140        tools._FinaliseForTest()
141
142    def setUp(self):
143        self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
144        self.node = self.dtb.GetNode('/spl-test')
145        self.fdt = self.dtb.GetFdtObj()
146
147    def testGetEmpty(self):
148        """Tests the GetEmpty() function for the various supported types"""
149        self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL))
150        self.assertEqual(chr(0), fdt.Prop.GetEmpty(fdt.TYPE_BYTE))
151        self.assertEqual(chr(0) * 4, fdt.Prop.GetEmpty(fdt.TYPE_INT))
152        self.assertEqual('', fdt.Prop.GetEmpty(fdt.TYPE_STRING))
153
154    def testGetOffset(self):
155        """Test we can get the offset of a property"""
156        prop = self.node.props['longbytearray']
157
158        # Add 12, which is sizeof(struct fdt_property), to get to start of data
159        offset = prop.GetOffset() + 12
160        data = self.dtb._fdt[offset:offset + len(prop.value)]
161        bytes = [chr(x) for x in data]
162        self.assertEqual(bytes, prop.value)
163
164    def testWiden(self):
165        """Test widening of values"""
166        node2 = self.dtb.GetNode('/spl-test2')
167        prop = self.node.props['intval']
168
169        # No action
170        prop2 = node2.props['intval']
171        prop.Widen(prop2)
172        self.assertEqual(fdt.TYPE_INT, prop.type)
173        self.assertEqual(1, fdt32_to_cpu(prop.value))
174
175        # Convert singla value to array
176        prop2 = self.node.props['intarray']
177        prop.Widen(prop2)
178        self.assertEqual(fdt.TYPE_INT, prop.type)
179        self.assertTrue(isinstance(prop.value, list))
180
181        # A 4-byte array looks like a single integer. When widened by a longer
182        # byte array, it should turn into an array.
183        prop = self.node.props['longbytearray']
184        prop2 = node2.props['longbytearray']
185        self.assertFalse(isinstance(prop2.value, list))
186        self.assertEqual(4, len(prop2.value))
187        prop2.Widen(prop)
188        self.assertTrue(isinstance(prop2.value, list))
189        self.assertEqual(9, len(prop2.value))
190
191        # Similarly for a string array
192        prop = self.node.props['stringval']
193        prop2 = node2.props['stringarray']
194        self.assertFalse(isinstance(prop.value, list))
195        self.assertEqual(7, len(prop.value))
196        prop.Widen(prop2)
197        self.assertTrue(isinstance(prop.value, list))
198        self.assertEqual(3, len(prop.value))
199
200        # Enlarging an existing array
201        prop = self.node.props['stringarray']
202        prop2 = node2.props['stringarray']
203        self.assertTrue(isinstance(prop.value, list))
204        self.assertEqual(2, len(prop.value))
205        prop.Widen(prop2)
206        self.assertTrue(isinstance(prop.value, list))
207        self.assertEqual(3, len(prop.value))
208
209
210def RunTests(args):
211    """Run all the test we have for the fdt model
212
213    Args:
214        args: List of positional args provided to fdt. This can hold a test
215            name to execute (as in 'fdt -t testFdt', for example)
216    """
217    result = unittest.TestResult()
218    sys.argv = [sys.argv[0]]
219    test_name = args and args[0] or None
220    for module in (TestFdt, TestNode, TestProp):
221        if test_name:
222            try:
223                suite = unittest.TestLoader().loadTestsFromName(test_name, module)
224            except AttributeError:
225                continue
226        else:
227            suite = unittest.TestLoader().loadTestsFromTestCase(module)
228        suite.run(result)
229
230    print result
231    for _, err in result.errors:
232        print err
233    for _, err in result.failures:
234        print err
235
236if __name__ != '__main__':
237    sys.exit(1)
238
239parser = OptionParser()
240parser.add_option('-t', '--test', action='store_true', dest='test',
241                  default=False, help='run tests')
242(options, args) = parser.parse_args()
243
244# Run our meagre tests
245if options.test:
246    RunTests(args)
247