blob: 3b8ee00d4e0bc947c62604d7c2f7a3a98e254b58 [file] [log] [blame]
Simon Glassf7ba5f02019-10-31 07:42:54 -06001#!/usr/bin/env python3
Simon Glass2ba98752018-07-06 10:27:24 -06002# SPDX-License-Identifier: GPL-2.0+
Simon Glass5d1637a2022-07-30 20:57:10 -06003
4"""
5Tests for the Fdt module
6Copyright (c) 2018 Google, Inc
7Written by Simon Glass <sjg@chromium.org>
8"""
Simon Glass2ba98752018-07-06 10:27:24 -06009
Simon Glass7640b162022-07-30 20:57:09 -060010from argparse import ArgumentParser
Simon Glass2ba98752018-07-06 10:27:24 -060011import os
Simon Glassa004f292019-07-20 12:23:49 -060012import shutil
Simon Glass2ba98752018-07-06 10:27:24 -060013import sys
Simon Glassa004f292019-07-20 12:23:49 -060014import tempfile
Simon Glass2ba98752018-07-06 10:27:24 -060015import unittest
16
17# Bring in the patman libraries
18our_path = os.path.dirname(os.path.realpath(__file__))
Simon Glassb4fa9492020-04-17 18:09:05 -060019sys.path.insert(1, os.path.join(our_path, '..'))
Simon Glass2ba98752018-07-06 10:27:24 -060020
Simon Glassff139b62021-11-23 11:03:38 -070021# Bring in the libfdt module
22sys.path.insert(2, 'scripts/dtc/pylibfdt')
23sys.path.insert(2, os.path.join(our_path, '../../scripts/dtc/pylibfdt'))
24sys.path.insert(2, os.path.join(our_path,
25 '../../build-sandbox_spl/scripts/dtc/pylibfdt'))
26
Simon Glass5d1637a2022-07-30 20:57:10 -060027#pylint: disable=wrong-import-position
Simon Glassbf776672020-04-17 18:09:04 -060028from dtoc import fdt
29from dtoc import fdt_util
Simon Glassd866e622021-11-23 11:03:39 -070030from dtoc.fdt_util import fdt32_to_cpu, fdt64_to_cpu
Simon Glass8a455fc2022-02-11 13:23:20 -070031from dtoc.fdt import Type, BytesToValue
Simon Glass2ba98752018-07-06 10:27:24 -060032import libfdt
Simon Glassbf776672020-04-17 18:09:04 -060033from patman import test_util
34from patman import tools
Simon Glass2ba98752018-07-06 10:27:24 -060035
Simon Glass5d1637a2022-07-30 20:57:10 -060036#pylint: disable=protected-access
37
38def _get_property_value(dtb, node, prop_name):
Simon Glassf9b88b32018-07-06 10:27:29 -060039 """Low-level function to get the property value based on its offset
40
41 This looks directly in the device tree at the property's offset to find
42 its value. It is useful as a check that the property is in the correct
43 place.
44
45 Args:
46 node: Node to look in
47 prop_name: Property name to find
48
49 Returns:
50 Tuple:
51 Prop object found
52 Value of property as a string (found using property offset)
53 """
54 prop = node.props[prop_name]
55
56 # Add 12, which is sizeof(struct fdt_property), to get to start of data
57 offset = prop.GetOffset() + 12
58 data = dtb.GetContents()[offset:offset + len(prop.value)]
Simon Glass479dd302020-11-08 20:36:20 -070059 return prop, [chr(x) for x in data]
Simon Glassf9b88b32018-07-06 10:27:29 -060060
Simon Glassdff51a52021-02-03 06:00:56 -070061def find_dtb_file(dts_fname):
62 """Locate a test file in the test/ directory
63
64 Args:
65 dts_fname (str): Filename to find, e.g. 'dtoc_test_simple.dts]
66
67 Returns:
68 str: Path to the test filename
69 """
70 return os.path.join('tools/dtoc/test', dts_fname)
71
Simon Glassf9b88b32018-07-06 10:27:29 -060072
Simon Glass2ba98752018-07-06 10:27:24 -060073class TestFdt(unittest.TestCase):
74 """Tests for the Fdt module
75
76 This includes unit tests for some functions and functional tests for the fdt
77 module.
78 """
79 @classmethod
80 def setUpClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -070081 tools.prepare_output_dir(None)
Simon Glass2ba98752018-07-06 10:27:24 -060082
83 @classmethod
84 def tearDownClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -070085 tools.finalise_output_dir()
Simon Glass2ba98752018-07-06 10:27:24 -060086
87 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -070088 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -060089
Simon Glass5d1637a2022-07-30 20:57:10 -060090 def test_fdt(self):
Simon Glass2ba98752018-07-06 10:27:24 -060091 """Test that we can open an Fdt"""
92 self.dtb.Scan()
93 root = self.dtb.GetRoot()
94 self.assertTrue(isinstance(root, fdt.Node))
95
Simon Glass5d1637a2022-07-30 20:57:10 -060096 def test_get_node(self):
Simon Glass2ba98752018-07-06 10:27:24 -060097 """Test the GetNode() method"""
98 node = self.dtb.GetNode('/spl-test')
99 self.assertTrue(isinstance(node, fdt.Node))
Simon Glasse44bc832019-07-20 12:23:39 -0600100
Simon Glass2ba98752018-07-06 10:27:24 -0600101 node = self.dtb.GetNode('/i2c@0/pmic@9')
102 self.assertTrue(isinstance(node, fdt.Node))
103 self.assertEqual('pmic@9', node.name)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600104 self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
Simon Glass2ba98752018-07-06 10:27:24 -0600105
Simon Glasse44bc832019-07-20 12:23:39 -0600106 node = self.dtb.GetNode('/')
107 self.assertTrue(isinstance(node, fdt.Node))
108 self.assertEqual(0, node.Offset())
109
Simon Glass5d1637a2022-07-30 20:57:10 -0600110 def test_flush(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600111 """Check that we can flush the device tree out to its file"""
112 fname = self.dtb._fname
Simon Glass5d1637a2022-07-30 20:57:10 -0600113 with open(fname, 'rb') as inf:
114 inf.read()
Simon Glass2ba98752018-07-06 10:27:24 -0600115 os.remove(fname)
116 with self.assertRaises(IOError):
Simon Glass5d1637a2022-07-30 20:57:10 -0600117 with open(fname, 'rb'):
118 pass
Simon Glass2ba98752018-07-06 10:27:24 -0600119 self.dtb.Flush()
Simon Glass5d1637a2022-07-30 20:57:10 -0600120 with open(fname, 'rb') as inf:
121 inf.read()
Simon Glass2ba98752018-07-06 10:27:24 -0600122
Simon Glass5d1637a2022-07-30 20:57:10 -0600123 def test_pack(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600124 """Test that packing a device tree works"""
125 self.dtb.Pack()
126
Simon Glass5d1637a2022-07-30 20:57:10 -0600127 def test_get_fdt_raw(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600128 """Tetst that we can access the raw device-tree data"""
Simon Glass8a455fc2022-02-11 13:23:20 -0700129 self.assertTrue(isinstance(self.dtb.GetContents(), bytes))
Simon Glass2ba98752018-07-06 10:27:24 -0600130
Simon Glass5d1637a2022-07-30 20:57:10 -0600131 def test_get_props(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600132 """Tests obtaining a list of properties"""
133 node = self.dtb.GetNode('/spl-test')
134 props = self.dtb.GetProps(node)
135 self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
Simon Glassd866e622021-11-23 11:03:39 -0700136 'int64val', 'intarray', 'intval', 'longbytearray',
Simon Glasseec44c72021-07-28 19:23:11 -0600137 'maybe-empty-int', 'notstring', 'stringarray',
138 'stringval', 'u-boot,dm-pre-reloc'],
Simon Glass2ba98752018-07-06 10:27:24 -0600139 sorted(props.keys()))
140
Simon Glass5d1637a2022-07-30 20:57:10 -0600141 def test_check_error(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600142 """Tests the ChecKError() function"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600143 with self.assertRaises(ValueError) as exc:
Simon Glass2a2d91d2018-07-06 10:27:28 -0600144 fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
Simon Glass5d1637a2022-07-30 20:57:10 -0600145 self.assertIn('FDT_ERR_NOTFOUND: hello', str(exc.exception))
Simon Glass2ba98752018-07-06 10:27:24 -0600146
Simon Glass5d1637a2022-07-30 20:57:10 -0600147 def test_get_fdt(self):
148 """Test getting an Fdt object from a node"""
Simon Glass94a7c602018-07-17 13:25:46 -0600149 node = self.dtb.GetNode('/spl-test')
150 self.assertEqual(self.dtb, node.GetFdt())
Simon Glass2ba98752018-07-06 10:27:24 -0600151
Simon Glass5d1637a2022-07-30 20:57:10 -0600152 def test_bytes_to_value(self):
153 """Test converting a string list into Python"""
Simon Glassb5f0daf2019-05-17 22:00:41 -0600154 self.assertEqual(BytesToValue(b'this\0is\0'),
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700155 (Type.STRING, ['this', 'is']))
Simon Glassb5f0daf2019-05-17 22:00:41 -0600156
Simon Glass2ba98752018-07-06 10:27:24 -0600157class TestNode(unittest.TestCase):
158 """Test operation of the Node class"""
159
160 @classmethod
161 def setUpClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700162 tools.prepare_output_dir(None)
Simon Glass2ba98752018-07-06 10:27:24 -0600163
164 @classmethod
165 def tearDownClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700166 tools.finalise_output_dir()
Simon Glass2ba98752018-07-06 10:27:24 -0600167
168 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700169 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -0600170 self.node = self.dtb.GetNode('/spl-test')
Simon Glass76677dd2021-03-21 18:24:37 +1300171 self.fdt = self.dtb.GetFdtObj()
Simon Glass2ba98752018-07-06 10:27:24 -0600172
Simon Glass5d1637a2022-07-30 20:57:10 -0600173 def test_offset(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600174 """Tests that we can obtain the offset of a node"""
175 self.assertTrue(self.node.Offset() > 0)
176
Simon Glass5d1637a2022-07-30 20:57:10 -0600177 def test_delete(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600178 """Tests that we can delete a property"""
179 node2 = self.dtb.GetNode('/spl-test2')
180 offset1 = node2.Offset()
181 self.node.DeleteProp('intval')
182 offset2 = node2.Offset()
183 self.assertTrue(offset2 < offset1)
184 self.node.DeleteProp('intarray')
185 offset3 = node2.Offset()
186 self.assertTrue(offset3 < offset2)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600187 with self.assertRaises(libfdt.FdtException):
188 self.node.DeleteProp('missing')
Simon Glass2ba98752018-07-06 10:27:24 -0600189
Simon Glass5d1637a2022-07-30 20:57:10 -0600190 def test_delete_get_offset(self):
Simon Glassf9b88b32018-07-06 10:27:29 -0600191 """Test that property offset update when properties are deleted"""
192 self.node.DeleteProp('intval')
Simon Glass5d1637a2022-07-30 20:57:10 -0600193 prop, value = _get_property_value(self.dtb, self.node, 'longbytearray')
Simon Glassf9b88b32018-07-06 10:27:29 -0600194 self.assertEqual(prop.value, value)
195
Simon Glass5d1637a2022-07-30 20:57:10 -0600196 def test_find_node(self):
Simon Glass1d858882018-07-17 13:25:41 -0600197 """Tests that we can find a node using the FindNode() functoin"""
198 node = self.dtb.GetRoot().FindNode('i2c@0')
Simon Glass2ba98752018-07-06 10:27:24 -0600199 self.assertEqual('i2c@0', node.name)
Simon Glass1d858882018-07-17 13:25:41 -0600200 subnode = node.FindNode('pmic@9')
Simon Glass2ba98752018-07-06 10:27:24 -0600201 self.assertEqual('pmic@9', subnode.name)
Simon Glass1d858882018-07-17 13:25:41 -0600202 self.assertEqual(None, node.FindNode('missing'))
Simon Glass2ba98752018-07-06 10:27:24 -0600203
Simon Glass5d1637a2022-07-30 20:57:10 -0600204 def test_refresh_missing_node(self):
Simon Glassf9b88b32018-07-06 10:27:29 -0600205 """Test refreshing offsets when an extra node is present in dtb"""
206 # Delete it from our tables, not the device tree
207 del self.dtb._root.subnodes[-1]
Simon Glass5d1637a2022-07-30 20:57:10 -0600208 with self.assertRaises(ValueError) as exc:
Simon Glassf9b88b32018-07-06 10:27:29 -0600209 self.dtb.Refresh()
Simon Glass5d1637a2022-07-30 20:57:10 -0600210 self.assertIn('Internal error, offset', str(exc.exception))
Simon Glassf9b88b32018-07-06 10:27:29 -0600211
Simon Glass5d1637a2022-07-30 20:57:10 -0600212 def test_refresh_extra_node(self):
Simon Glassf9b88b32018-07-06 10:27:29 -0600213 """Test refreshing offsets when an expected node is missing"""
214 # Delete it from the device tre, not our tables
Simon Glass76677dd2021-03-21 18:24:37 +1300215 self.fdt.del_node(self.node.Offset())
Simon Glass5d1637a2022-07-30 20:57:10 -0600216 with self.assertRaises(ValueError) as exc:
Simon Glassf9b88b32018-07-06 10:27:29 -0600217 self.dtb.Refresh()
218 self.assertIn('Internal error, node name mismatch '
Simon Glass5d1637a2022-07-30 20:57:10 -0600219 'spl-test != spl-test2', str(exc.exception))
Simon Glassf9b88b32018-07-06 10:27:29 -0600220
Simon Glass5d1637a2022-07-30 20:57:10 -0600221 def test_refresh_missing_prop(self):
Simon Glassf9b88b32018-07-06 10:27:29 -0600222 """Test refreshing offsets when an extra property is present in dtb"""
223 # Delete it from our tables, not the device tree
224 del self.node.props['notstring']
Simon Glass5d1637a2022-07-30 20:57:10 -0600225 with self.assertRaises(ValueError) as exc:
Simon Glassf9b88b32018-07-06 10:27:29 -0600226 self.dtb.Refresh()
Simon Glassacd98612021-03-21 18:24:34 +1300227 self.assertIn("Internal error, node '/spl-test' property 'notstring' missing, offset ",
Simon Glass5d1637a2022-07-30 20:57:10 -0600228 str(exc.exception))
Simon Glassf9b88b32018-07-06 10:27:29 -0600229
Simon Glass5d1637a2022-07-30 20:57:10 -0600230 def test_lookup_phandle(self):
Simon Glass94a7c602018-07-17 13:25:46 -0600231 """Test looking up a single phandle"""
Simon Glassdff51a52021-02-03 06:00:56 -0700232 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass94a7c602018-07-17 13:25:46 -0600233 node = dtb.GetNode('/phandle-source2')
234 prop = node.props['clocks']
235 target = dtb.GetNode('/phandle-target')
236 self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
237
Simon Glass5d1637a2022-07-30 20:57:10 -0600238 def test_add_node_space(self):
Simon Glass76677dd2021-03-21 18:24:37 +1300239 """Test adding a single node when out of space"""
240 self.fdt.pack()
241 self.node.AddSubnode('subnode')
Simon Glass5d1637a2022-07-30 20:57:10 -0600242 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glass76677dd2021-03-21 18:24:37 +1300243 self.dtb.Sync(auto_resize=False)
Simon Glass5d1637a2022-07-30 20:57:10 -0600244 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glass76677dd2021-03-21 18:24:37 +1300245
246 self.dtb.Sync(auto_resize=True)
247 offset = self.fdt.path_offset('/spl-test/subnode')
248 self.assertTrue(offset > 0)
249
Simon Glass5d1637a2022-07-30 20:57:10 -0600250 def test_add_nodes(self):
Simon Glass76677dd2021-03-21 18:24:37 +1300251 """Test adding various subnode and properies"""
252 node = self.dtb.GetNode('/i2c@0')
253
Simon Glassf6176652021-03-21 18:24:38 +1300254 # Add one more node next to the pmic one
255 sn1 = node.AddSubnode('node-one')
256 sn1.AddInt('integer-a', 12)
257 sn1.AddInt('integer-b', 23)
258
259 # Sync so that everything is clean
260 self.dtb.Sync(auto_resize=True)
261
262 # Add two subnodes next to pmic and node-one
263 sn2 = node.AddSubnode('node-two')
264 sn2.AddInt('integer-2a', 34)
265 sn2.AddInt('integer-2b', 45)
266
267 sn3 = node.AddSubnode('node-three')
268 sn3.AddInt('integer-3', 123)
269
Simon Glass76677dd2021-03-21 18:24:37 +1300270 # Add a property to the node after i2c@0 to check that this is not
271 # disturbed by adding a subnode to i2c@0
272 orig_node = self.dtb.GetNode('/orig-node')
273 orig_node.AddInt('integer-4', 456)
274
275 # Add a property to the pmic node to check that pmic properties are not
276 # disturbed
277 pmic = self.dtb.GetNode('/i2c@0/pmic@9')
278 pmic.AddInt('integer-5', 567)
279
280 self.dtb.Sync(auto_resize=True)
281
Simon Glass5d1637a2022-07-30 20:57:10 -0600282 def test_add_one_node(self):
Simon Glassdd857ee2022-02-08 11:49:52 -0700283 """Testing deleting and adding a subnode before syncing"""
284 subnode = self.node.AddSubnode('subnode')
285 self.node.AddSubnode('subnode2')
286 self.dtb.Sync(auto_resize=True)
287
288 # Delete a node and add a new one
289 subnode.Delete()
290 self.node.AddSubnode('subnode3')
291 self.dtb.Sync()
292
Simon Glass5d1637a2022-07-30 20:57:10 -0600293 def test_refresh_name_mismatch(self):
Simon Glass5d1bec32021-03-21 18:24:39 +1300294 """Test name mismatch when syncing nodes and properties"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600295 self.node.AddInt('integer-a', 12)
Simon Glass5d1bec32021-03-21 18:24:39 +1300296
297 wrong_offset = self.dtb.GetNode('/i2c@0')._offset
298 self.node._offset = wrong_offset
Simon Glass5d1637a2022-07-30 20:57:10 -0600299 with self.assertRaises(ValueError) as exc:
Simon Glass5d1bec32021-03-21 18:24:39 +1300300 self.dtb.Sync()
301 self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600302 str(exc.exception))
Simon Glass5d1bec32021-03-21 18:24:39 +1300303
Simon Glass5d1637a2022-07-30 20:57:10 -0600304 with self.assertRaises(ValueError) as exc:
Simon Glass5d1bec32021-03-21 18:24:39 +1300305 self.node.Refresh(wrong_offset)
306 self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600307 str(exc.exception))
Simon Glass5d1bec32021-03-21 18:24:39 +1300308
Simon Glass2ba98752018-07-06 10:27:24 -0600309
310class TestProp(unittest.TestCase):
311 """Test operation of the Prop class"""
312
313 @classmethod
314 def setUpClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700315 tools.prepare_output_dir(None)
Simon Glass2ba98752018-07-06 10:27:24 -0600316
317 @classmethod
318 def tearDownClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700319 tools.finalise_output_dir()
Simon Glass2ba98752018-07-06 10:27:24 -0600320
321 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700322 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -0600323 self.node = self.dtb.GetNode('/spl-test')
324 self.fdt = self.dtb.GetFdtObj()
325
Simon Glass5d1637a2022-07-30 20:57:10 -0600326 def test_missing_node(self):
327 """Test GetNode() when the node is missing"""
Simon Glassb9066ff2018-07-06 10:27:30 -0600328 self.assertEqual(None, self.dtb.GetNode('missing'))
329
Simon Glass5d1637a2022-07-30 20:57:10 -0600330 def test_phandle(self):
331 """Test GetNode() on a phandle"""
Simon Glassdff51a52021-02-03 06:00:56 -0700332 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass760b7172018-07-06 10:27:31 -0600333 node = dtb.GetNode('/phandle-source2')
334 prop = node.props['clocks']
335 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600336
Simon Glass5d1637a2022-07-30 20:57:10 -0600337 def _convert_prop(self, prop_name):
Simon Glass2a2d91d2018-07-06 10:27:28 -0600338 """Helper function to look up a property in self.node and return it
339
340 Args:
Simon Glass5d1637a2022-07-30 20:57:10 -0600341 str: Property name to find
Simon Glass2a2d91d2018-07-06 10:27:28 -0600342
Simon Glass5d1637a2022-07-30 20:57:10 -0600343 Returns:
344 fdt.Prop: object for this property
Simon Glass2a2d91d2018-07-06 10:27:28 -0600345 """
Simon Glass5d1637a2022-07-30 20:57:10 -0600346 prop = self.fdt.getprop(self.node.Offset(), prop_name)
347 return fdt.Prop(self.node, -1, prop_name, prop)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600348
Simon Glass5d1637a2022-07-30 20:57:10 -0600349 def test_make_prop(self):
Simon Glass2a2d91d2018-07-06 10:27:28 -0600350 """Test we can convert all the the types that are supported"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600351 prop = self._convert_prop('boolval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700352 self.assertEqual(Type.BOOL, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600353 self.assertEqual(True, prop.value)
354
Simon Glass5d1637a2022-07-30 20:57:10 -0600355 prop = self._convert_prop('intval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700356 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600357 self.assertEqual(1, fdt32_to_cpu(prop.value))
358
Simon Glass5d1637a2022-07-30 20:57:10 -0600359 prop = self._convert_prop('int64val')
Simon Glassd866e622021-11-23 11:03:39 -0700360 self.assertEqual(Type.INT, prop.type)
361 self.assertEqual(0x123456789abcdef0, fdt64_to_cpu(prop.value))
362
Simon Glass5d1637a2022-07-30 20:57:10 -0600363 prop = self._convert_prop('intarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700364 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600365 val = [fdt32_to_cpu(val) for val in prop.value]
366 self.assertEqual([2, 3, 4], val)
367
Simon Glass5d1637a2022-07-30 20:57:10 -0600368 prop = self._convert_prop('byteval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700369 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600370 self.assertEqual(5, ord(prop.value))
371
Simon Glass5d1637a2022-07-30 20:57:10 -0600372 prop = self._convert_prop('longbytearray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700373 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600374 val = [ord(val) for val in prop.value]
375 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
376
Simon Glass5d1637a2022-07-30 20:57:10 -0600377 prop = self._convert_prop('stringval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700378 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600379 self.assertEqual('message', prop.value)
380
Simon Glass5d1637a2022-07-30 20:57:10 -0600381 prop = self._convert_prop('stringarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700382 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600383 self.assertEqual(['multi-word', 'message'], prop.value)
384
Simon Glass5d1637a2022-07-30 20:57:10 -0600385 prop = self._convert_prop('notstring')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700386 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600387 val = [ord(val) for val in prop.value]
388 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
389
Simon Glass5d1637a2022-07-30 20:57:10 -0600390 def test_get_empty(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600391 """Tests the GetEmpty() function for the various supported types"""
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700392 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
393 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
Simon Glassc1aa66e2022-01-29 14:14:04 -0700394 self.assertEqual(tools.get_bytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700395 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass2ba98752018-07-06 10:27:24 -0600396
Simon Glass5d1637a2022-07-30 20:57:10 -0600397 def test_get_offset(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600398 """Test we can get the offset of a property"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600399 prop, value = _get_property_value(self.dtb, self.node, 'longbytearray')
Simon Glassf9b88b32018-07-06 10:27:29 -0600400 self.assertEqual(prop.value, value)
Simon Glass2ba98752018-07-06 10:27:24 -0600401
Simon Glass5d1637a2022-07-30 20:57:10 -0600402 def test_widen(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600403 """Test widening of values"""
404 node2 = self.dtb.GetNode('/spl-test2')
Simon Glasse144caf2020-10-03 11:31:27 -0600405 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass2ba98752018-07-06 10:27:24 -0600406 prop = self.node.props['intval']
407
408 # No action
409 prop2 = node2.props['intval']
410 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700411 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600412 self.assertEqual(1, fdt32_to_cpu(prop.value))
413
Simon Glassca044942021-07-28 19:23:10 -0600414 # Convert single value to array
Simon Glass2ba98752018-07-06 10:27:24 -0600415 prop2 = self.node.props['intarray']
416 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700417 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600418 self.assertTrue(isinstance(prop.value, list))
419
420 # A 4-byte array looks like a single integer. When widened by a longer
421 # byte array, it should turn into an array.
422 prop = self.node.props['longbytearray']
423 prop2 = node2.props['longbytearray']
Simon Glasse144caf2020-10-03 11:31:27 -0600424 prop3 = node3.props['longbytearray']
Simon Glass2ba98752018-07-06 10:27:24 -0600425 self.assertFalse(isinstance(prop2.value, list))
426 self.assertEqual(4, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600427 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600428 prop2.Widen(prop)
429 self.assertTrue(isinstance(prop2.value, list))
430 self.assertEqual(9, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600431 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
432 '\0', '\0', '\0', '\0'], prop2.value)
433 prop3.Widen(prop)
434 self.assertTrue(isinstance(prop3.value, list))
435 self.assertEqual(9, len(prop3.value))
436 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
437 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600438
Simon Glass5d1637a2022-07-30 20:57:10 -0600439 def test_widen_more(self):
440 """More tests of widening values"""
441 node2 = self.dtb.GetNode('/spl-test2')
442 node3 = self.dtb.GetNode('/spl-test3')
443 prop = self.node.props['intval']
444
445 # Test widening a single string into a string array
Simon Glass2ba98752018-07-06 10:27:24 -0600446 prop = self.node.props['stringval']
447 prop2 = node2.props['stringarray']
448 self.assertFalse(isinstance(prop.value, list))
449 self.assertEqual(7, len(prop.value))
450 prop.Widen(prop2)
451 self.assertTrue(isinstance(prop.value, list))
452 self.assertEqual(3, len(prop.value))
453
454 # Enlarging an existing array
455 prop = self.node.props['stringarray']
456 prop2 = node2.props['stringarray']
457 self.assertTrue(isinstance(prop.value, list))
458 self.assertEqual(2, len(prop.value))
459 prop.Widen(prop2)
460 self.assertTrue(isinstance(prop.value, list))
461 self.assertEqual(3, len(prop.value))
462
Simon Glassca044942021-07-28 19:23:10 -0600463 # Widen an array of ints with an int (should do nothing)
464 prop = self.node.props['intarray']
Simon Glasse679f392021-08-02 07:37:54 -0600465 prop2 = node2.props['intval']
Simon Glassca044942021-07-28 19:23:10 -0600466 self.assertEqual(Type.INT, prop.type)
467 self.assertEqual(3, len(prop.value))
468 prop.Widen(prop2)
469 self.assertEqual(Type.INT, prop.type)
470 self.assertEqual(3, len(prop.value))
471
Simon Glasseec44c72021-07-28 19:23:11 -0600472 # Widen an empty bool to an int
473 prop = self.node.props['maybe-empty-int']
474 prop3 = node3.props['maybe-empty-int']
475 self.assertEqual(Type.BOOL, prop.type)
476 self.assertEqual(True, prop.value)
477 self.assertEqual(Type.INT, prop3.type)
478 self.assertFalse(isinstance(prop.value, list))
479 self.assertEqual(4, len(prop3.value))
480 prop.Widen(prop3)
481 self.assertEqual(Type.INT, prop.type)
482 self.assertTrue(isinstance(prop.value, list))
483 self.assertEqual(1, len(prop.value))
484
Simon Glass5d1637a2022-07-30 20:57:10 -0600485 def test_add(self):
Simon Glass116adec2018-07-06 10:27:38 -0600486 """Test adding properties"""
487 self.fdt.pack()
488 # This function should automatically expand the device tree
489 self.node.AddZeroProp('one')
490 self.node.AddZeroProp('two')
491 self.node.AddZeroProp('three')
Simon Glassfa80c252018-09-14 04:57:13 -0600492 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600493
494 # Updating existing properties should be OK, since the device-tree size
495 # does not change
496 self.fdt.pack()
497 self.node.SetInt('one', 1)
498 self.node.SetInt('two', 2)
499 self.node.SetInt('three', 3)
Simon Glassfa80c252018-09-14 04:57:13 -0600500 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600501
502 # This should fail since it would need to increase the device-tree size
Simon Glassfa80c252018-09-14 04:57:13 -0600503 self.node.AddZeroProp('four')
Simon Glass5d1637a2022-07-30 20:57:10 -0600504 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glassfa80c252018-09-14 04:57:13 -0600505 self.dtb.Sync(auto_resize=False)
Simon Glass5d1637a2022-07-30 20:57:10 -0600506 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glass64349612018-09-14 04:57:16 -0600507 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600508
Simon Glass5d1637a2022-07-30 20:57:10 -0600509 def test_add_more(self):
Simon Glass64349612018-09-14 04:57:16 -0600510 """Test various other methods for adding and setting properties"""
511 self.node.AddZeroProp('one')
512 self.dtb.Sync(auto_resize=True)
513 data = self.fdt.getprop(self.node.Offset(), 'one')
514 self.assertEqual(0, fdt32_to_cpu(data))
515
516 self.node.SetInt('one', 1)
517 self.dtb.Sync(auto_resize=False)
518 data = self.fdt.getprop(self.node.Offset(), 'one')
519 self.assertEqual(1, fdt32_to_cpu(data))
520
Simon Glass6eb99322021-01-06 21:35:18 -0700521 val = 1234
522 self.node.AddInt('integer', val)
523 self.dtb.Sync(auto_resize=True)
524 data = self.fdt.getprop(self.node.Offset(), 'integer')
525 self.assertEqual(val, fdt32_to_cpu(data))
526
Simon Glass64349612018-09-14 04:57:16 -0600527 val = '123' + chr(0) + '456'
528 self.node.AddString('string', val)
529 self.dtb.Sync(auto_resize=True)
530 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700531 self.assertEqual(tools.to_bytes(val) + b'\0', data)
Simon Glass64349612018-09-14 04:57:16 -0600532
533 self.fdt.pack()
534 self.node.SetString('string', val + 'x')
Simon Glass5d1637a2022-07-30 20:57:10 -0600535 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glass64349612018-09-14 04:57:16 -0600536 self.dtb.Sync(auto_resize=False)
Simon Glass5d1637a2022-07-30 20:57:10 -0600537 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glass64349612018-09-14 04:57:16 -0600538 self.node.SetString('string', val[:-1])
539
540 prop = self.node.props['string']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700541 prop.SetData(tools.to_bytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600542 self.dtb.Sync(auto_resize=False)
543 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700544 self.assertEqual(tools.to_bytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600545
546 self.node.AddEmptyProp('empty', 5)
547 self.dtb.Sync(auto_resize=True)
548 prop = self.node.props['empty']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700549 prop.SetData(tools.to_bytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600550 self.dtb.Sync(auto_resize=False)
551 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700552 self.assertEqual(tools.to_bytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600553
Simon Glassf6b64812019-05-17 22:00:36 -0600554 self.node.SetData('empty', b'123')
555 self.assertEqual(b'123', prop.bytes)
Simon Glass64349612018-09-14 04:57:16 -0600556
Simon Glassc0639172020-07-09 18:39:44 -0600557 # Trying adding a lot of data at once
Simon Glassc1aa66e2022-01-29 14:14:04 -0700558 self.node.AddData('data', tools.get_bytes(65, 20000))
Simon Glassc0639172020-07-09 18:39:44 -0600559 self.dtb.Sync(auto_resize=True)
560
Simon Glassbc116022022-02-08 11:49:50 -0700561 def test_string_list(self):
562 """Test adding string-list property to a node"""
563 val = ['123', '456']
564 self.node.AddStringList('stringlist', val)
565 self.dtb.Sync(auto_resize=True)
566 data = self.fdt.getprop(self.node.Offset(), 'stringlist')
567 self.assertEqual(b'123\x00456\0', data)
568
Simon Glass0ded4d42022-03-05 20:18:56 -0700569 val = []
570 self.node.AddStringList('stringlist', val)
571 self.dtb.Sync(auto_resize=True)
572 data = self.fdt.getprop(self.node.Offset(), 'stringlist')
573 self.assertEqual(b'', data)
574
Simon Glassa30c39f2022-02-08 11:49:51 -0700575 def test_delete_node(self):
576 """Test deleting a node"""
577 old_offset = self.fdt.path_offset('/spl-test')
578 self.assertGreater(old_offset, 0)
579 self.node.Delete()
580 self.dtb.Sync()
581 new_offset = self.fdt.path_offset('/spl-test', libfdt.QUIET_NOTFOUND)
582 self.assertEqual(-libfdt.NOTFOUND, new_offset)
583
Simon Glass5d1637a2022-07-30 20:57:10 -0600584 def test_from_data(self):
585 """Test creating an FDT from data"""
Simon Glass746aee32018-09-14 04:57:17 -0600586 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
587 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
588
589 self.node.AddEmptyProp('empty', 5)
590 self.dtb.Sync(auto_resize=True)
591 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
592
Simon Glass5d1637a2022-07-30 20:57:10 -0600593 def test_missing_set_int(self):
Simon Glassd9dad102019-07-20 12:23:37 -0600594 """Test handling of a missing property with SetInt"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600595 with self.assertRaises(ValueError) as exc:
Simon Glassd9dad102019-07-20 12:23:37 -0600596 self.node.SetInt('one', 1)
597 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600598 str(exc.exception))
Simon Glassd9dad102019-07-20 12:23:37 -0600599
Simon Glass5d1637a2022-07-30 20:57:10 -0600600 def test_missing_set_data(self):
Simon Glassd9dad102019-07-20 12:23:37 -0600601 """Test handling of a missing property with SetData"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600602 with self.assertRaises(ValueError) as exc:
Simon Glassd9dad102019-07-20 12:23:37 -0600603 self.node.SetData('one', b'data')
604 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600605 str(exc.exception))
Simon Glassd9dad102019-07-20 12:23:37 -0600606
Simon Glass5d1637a2022-07-30 20:57:10 -0600607 def test_missing_set_string(self):
Simon Glassd9dad102019-07-20 12:23:37 -0600608 """Test handling of a missing property with SetString"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600609 with self.assertRaises(ValueError) as exc:
Simon Glassd9dad102019-07-20 12:23:37 -0600610 self.node.SetString('one', 1)
611 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600612 str(exc.exception))
Simon Glassd9dad102019-07-20 12:23:37 -0600613
Simon Glass5d1637a2022-07-30 20:57:10 -0600614 def test_get_filename(self):
Simon Glassf6e02492019-07-20 12:24:08 -0600615 """Test the dtb filename can be provided"""
Simon Glassc1aa66e2022-01-29 14:14:04 -0700616 self.assertEqual(tools.get_output_filename('source.dtb'),
Simon Glassf6e02492019-07-20 12:24:08 -0600617 self.dtb.GetFilename())
618
Simon Glass2ba98752018-07-06 10:27:24 -0600619
Simon Glass2a2d91d2018-07-06 10:27:28 -0600620class TestFdtUtil(unittest.TestCase):
621 """Tests for the fdt_util module
622
623 This module will likely be mostly replaced at some point, once upstream
624 libfdt has better Python support. For now, this provides tests for current
625 functionality.
626 """
627 @classmethod
628 def setUpClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700629 tools.prepare_output_dir(None)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600630
Simon Glasse0e62752018-10-01 21:12:41 -0600631 @classmethod
632 def tearDownClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700633 tools.finalise_output_dir()
Simon Glasse0e62752018-10-01 21:12:41 -0600634
Simon Glass2a2d91d2018-07-06 10:27:28 -0600635 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700636 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600637 self.node = self.dtb.GetNode('/spl-test')
638
Simon Glass5d1637a2022-07-30 20:57:10 -0600639 def test_get_int(self):
640 """Test getting an int from a node"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600641 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
642 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
643
Simon Glass5d1637a2022-07-30 20:57:10 -0600644 with self.assertRaises(ValueError) as exc:
Simon Glassd866e622021-11-23 11:03:39 -0700645 fdt_util.GetInt(self.node, 'intarray')
Simon Glass2a2d91d2018-07-06 10:27:28 -0600646 self.assertIn("property 'intarray' has list value: expecting a single "
Simon Glass5d1637a2022-07-30 20:57:10 -0600647 'integer', str(exc.exception))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600648
Simon Glass5d1637a2022-07-30 20:57:10 -0600649 def test_get_int64(self):
650 """Test getting a 64-bit int from a node"""
Simon Glassd866e622021-11-23 11:03:39 -0700651 self.assertEqual(0x123456789abcdef0,
652 fdt_util.GetInt64(self.node, 'int64val'))
653 self.assertEqual(3, fdt_util.GetInt64(self.node, 'missing', 3))
654
Simon Glass5d1637a2022-07-30 20:57:10 -0600655 with self.assertRaises(ValueError) as exc:
Simon Glassd866e622021-11-23 11:03:39 -0700656 fdt_util.GetInt64(self.node, 'intarray')
657 self.assertIn(
658 "property 'intarray' should be a list with 2 items for 64-bit values",
Simon Glass5d1637a2022-07-30 20:57:10 -0600659 str(exc.exception))
Simon Glassd866e622021-11-23 11:03:39 -0700660
Simon Glass5d1637a2022-07-30 20:57:10 -0600661 def test_get_string(self):
662 """Test getting a string from a node"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600663 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
664 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
665 'test'))
Simon Glass0ded4d42022-03-05 20:18:56 -0700666 self.assertEqual('', fdt_util.GetString(self.node, 'boolval'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600667
Simon Glass5d1637a2022-07-30 20:57:10 -0600668 with self.assertRaises(ValueError) as exc:
Simon Glass2a2d91d2018-07-06 10:27:28 -0600669 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
670 self.assertIn("property 'stringarray' has list value: expecting a "
Simon Glass5d1637a2022-07-30 20:57:10 -0600671 'single string', str(exc.exception))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600672
Simon Glass5d1637a2022-07-30 20:57:10 -0600673 def test_get_string_list(self):
674 """Test getting a string list from a node"""
Simon Glass1b5a5332021-11-23 21:09:51 -0700675 self.assertEqual(['message'],
676 fdt_util.GetStringList(self.node, 'stringval'))
677 self.assertEqual(
678 ['multi-word', 'message'],
679 fdt_util.GetStringList(self.node, 'stringarray'))
680 self.assertEqual(['test'],
681 fdt_util.GetStringList(self.node, 'missing', ['test']))
Simon Glass0ded4d42022-03-05 20:18:56 -0700682 self.assertEqual([], fdt_util.GetStringList(self.node, 'boolval'))
Simon Glass1b5a5332021-11-23 21:09:51 -0700683
Simon Glass5d1637a2022-07-30 20:57:10 -0600684 def test_get_args(self):
685 """Test getting arguments from a node"""
Simon Glass7e4b66a2022-02-08 11:49:53 -0700686 node = self.dtb.GetNode('/orig-node')
687 self.assertEqual(['message'], fdt_util.GetArgs(self.node, 'stringval'))
688 self.assertEqual(
689 ['multi-word', 'message'],
690 fdt_util.GetArgs(self.node, 'stringarray'))
691 self.assertEqual([], fdt_util.GetArgs(self.node, 'boolval'))
Simon Glass61012532022-03-05 20:18:52 -0700692 self.assertEqual(['-n first', 'second', '-p', '123,456', '-x'],
Simon Glass7e4b66a2022-02-08 11:49:53 -0700693 fdt_util.GetArgs(node, 'args'))
Simon Glass61012532022-03-05 20:18:52 -0700694 self.assertEqual(['a space', 'there'],
695 fdt_util.GetArgs(node, 'args2'))
696 self.assertEqual(['-n', 'first', 'second', '-p', '123,456', '-x'],
697 fdt_util.GetArgs(node, 'args3'))
Simon Glass7e4b66a2022-02-08 11:49:53 -0700698 with self.assertRaises(ValueError) as exc:
699 fdt_util.GetArgs(self.node, 'missing')
700 self.assertIn(
701 "Node '/spl-test': Expected property 'missing'",
702 str(exc.exception))
703
Simon Glass5d1637a2022-07-30 20:57:10 -0600704 def test_get_bool(self):
705 """Test getting a bool from a node"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600706 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
707 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
708 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
709 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
710
Simon Glass5d1637a2022-07-30 20:57:10 -0600711 def test_get_byte(self):
712 """Test getting a byte from a node"""
Simon Glass3af8e492018-07-17 13:25:40 -0600713 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
714 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
715
Simon Glass5d1637a2022-07-30 20:57:10 -0600716 with self.assertRaises(ValueError) as exc:
Simon Glass3af8e492018-07-17 13:25:40 -0600717 fdt_util.GetByte(self.node, 'longbytearray')
718 self.assertIn("property 'longbytearray' has list value: expecting a "
Simon Glass5d1637a2022-07-30 20:57:10 -0600719 'single byte', str(exc.exception))
Simon Glass3af8e492018-07-17 13:25:40 -0600720
Simon Glass5d1637a2022-07-30 20:57:10 -0600721 with self.assertRaises(ValueError) as exc:
Simon Glass3af8e492018-07-17 13:25:40 -0600722 fdt_util.GetByte(self.node, 'intval')
723 self.assertIn("property 'intval' has length 4, expecting 1",
Simon Glass5d1637a2022-07-30 20:57:10 -0600724 str(exc.exception))
Simon Glass3af8e492018-07-17 13:25:40 -0600725
Simon Glass5d1637a2022-07-30 20:57:10 -0600726 def test_get_bytes(self):
727 """Test getting multiple bytes from a node"""
Simon Glass40b4d642021-11-23 11:03:40 -0700728 self.assertEqual(bytes([5]), fdt_util.GetBytes(self.node, 'byteval', 1))
729 self.assertEqual(None, fdt_util.GetBytes(self.node, 'missing', 3))
730 self.assertEqual(
731 bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3, bytes([3])))
732
Simon Glass5d1637a2022-07-30 20:57:10 -0600733 with self.assertRaises(ValueError) as exc:
Simon Glass40b4d642021-11-23 11:03:40 -0700734 fdt_util.GetBytes(self.node, 'longbytearray', 7)
735 self.assertIn(
736 "Node 'spl-test' property 'longbytearray' has length 9, expecting 7",
Simon Glass5d1637a2022-07-30 20:57:10 -0600737 str(exc.exception))
Simon Glass40b4d642021-11-23 11:03:40 -0700738
739 self.assertEqual(
740 bytes([0, 0, 0, 1]), fdt_util.GetBytes(self.node, 'intval', 4))
741 self.assertEqual(
742 bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3, bytes([3])))
743
Simon Glass5d1637a2022-07-30 20:57:10 -0600744 def test_get_phandle_list(self):
745 """Test getting a list of phandles from a node"""
Simon Glassdff51a52021-02-03 06:00:56 -0700746 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass94a7c602018-07-17 13:25:46 -0600747 node = dtb.GetNode('/phandle-source2')
748 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
749 node = dtb.GetNode('/phandle-source')
750 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
751 fdt_util.GetPhandleList(node, 'clocks'))
752 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
753
Simon Glass5d1637a2022-07-30 20:57:10 -0600754 def test_get_data_type(self):
755 """Test getting a value of a particular type from a node"""
Simon Glass53af22a2018-07-17 13:25:32 -0600756 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
757 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
758 str))
Simon Glass5d1637a2022-07-30 20:57:10 -0600759 with self.assertRaises(ValueError):
Simon Glass53af22a2018-07-17 13:25:32 -0600760 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
761 bool))
Simon Glass5d1637a2022-07-30 20:57:10 -0600762 def test_fdt_cells_to_cpu(self):
763 """Test getting cells with the correct endianness"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600764 val = self.node.props['intarray'].value
765 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
766 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
767
Simon Glassdff51a52021-02-03 06:00:56 -0700768 dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
Simon Glasse66d3182019-05-17 22:00:40 -0600769 node1 = dtb2.GetNode('/test1')
770 val = node1.props['reg'].value
Simon Glass2a2d91d2018-07-06 10:27:28 -0600771 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
772
Simon Glasse66d3182019-05-17 22:00:40 -0600773 node2 = dtb2.GetNode('/test2')
774 val = node2.props['reg'].value
775 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
776 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
777 2))
778 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
779
Simon Glass5d1637a2022-07-30 20:57:10 -0600780 def test_ensure_compiled(self):
Simon Glassa004f292019-07-20 12:23:49 -0600781 """Test a degenerate case of this function (file already compiled)"""
Simon Glassdff51a52021-02-03 06:00:56 -0700782 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600783 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
784
Simon Glass5d1637a2022-07-30 20:57:10 -0600785 def test_ensure_compiled_tmpdir(self):
Simon Glassa004f292019-07-20 12:23:49 -0600786 """Test providing a temporary directory"""
787 try:
788 old_outdir = tools.outdir
789 tools.outdir= None
790 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
Simon Glassdff51a52021-02-03 06:00:56 -0700791 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
Simon Glassa004f292019-07-20 12:23:49 -0600792 tmpdir)
793 self.assertEqual(tmpdir, os.path.dirname(dtb))
794 shutil.rmtree(tmpdir)
795 finally:
796 tools.outdir= old_outdir
797
Simon Glass8f5afe22023-01-11 16:10:18 -0700798 def test_get_phandle_name_offset(self):
799 val = fdt_util.GetPhandleNameOffset(self.node, 'missing')
800 self.assertIsNone(val)
801
802 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
803 node = dtb.GetNode('/phandle-source')
804 node, name, offset = fdt_util.GetPhandleNameOffset(node,
805 'phandle-name-offset')
806 self.assertEqual('phandle3-target', node.name)
807 self.assertEqual('fred', name)
808 self.assertEqual(123, offset)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600809
Simon Glass25980792022-07-30 20:57:05 -0600810def run_test_coverage(build_dir):
811 """Run the tests and check that we get 100% coverage
812
813 Args:
814 build_dir (str): Directory containing the build output
815 """
Simon Glass5e2ab402022-01-29 14:14:14 -0700816 test_util.run_test_coverage('tools/dtoc/test_fdt.py', None,
Simon Glass25980792022-07-30 20:57:05 -0600817 ['tools/patman/*.py', '*test_fdt.py'], build_dir)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600818
819
Simon Glass7640b162022-07-30 20:57:09 -0600820def run_tests(names, processes):
Simon Glass2ba98752018-07-06 10:27:24 -0600821 """Run all the test we have for the fdt model
822
823 Args:
Simon Glass7640b162022-07-30 20:57:09 -0600824 names (list of str): List of test names provided. Only the first is used
Simon Glassb26dd962022-07-30 20:57:06 -0600825 processes (int): Number of processes to use (None means as many as there
826 are CPUs on the system. This must be set to 1 when running under
827 the python3-coverage tool
Simon Glass42ae3632022-03-18 18:01:50 -0600828
829 Returns:
Simon Glassb26dd962022-07-30 20:57:06 -0600830 int: Return code, 0 on success
Simon Glass2ba98752018-07-06 10:27:24 -0600831 """
Simon Glass7640b162022-07-30 20:57:09 -0600832 test_name = names[0] if names else None
Alper Nebi Yasakd8318fe2022-04-02 20:06:06 +0300833 result = test_util.run_test_suites(
Simon Glassad744222022-07-30 20:57:07 -0600834 'test_fdt', False, False, False, processes, test_name, None,
Simon Glass42ae3632022-03-18 18:01:50 -0600835 [TestFdt, TestNode, TestProp, TestFdtUtil])
Simon Glass2ba98752018-07-06 10:27:24 -0600836
Alper Nebi Yasakd8318fe2022-04-02 20:06:06 +0300837 return (0 if result.wasSuccessful() else 1)
838
Simon Glass2ba98752018-07-06 10:27:24 -0600839
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600840def main():
841 """Main program for this tool"""
Simon Glass7640b162022-07-30 20:57:09 -0600842 parser = ArgumentParser()
843 parser.add_argument('-B', '--build-dir', type=str, default='b',
844 help='Directory containing the build output')
845 parser.add_argument('-P', '--processes', type=int,
846 help='set number of processes to use for running tests')
847 parser.add_argument('-t', '--test', action='store_true', dest='test',
848 default=False, help='run tests')
849 parser.add_argument('-T', '--test-coverage', action='store_true',
850 default=False,
851 help='run tests and check for 100% coverage')
852 parser.add_argument('name', nargs='*')
853 args = parser.parse_args()
Simon Glass2ba98752018-07-06 10:27:24 -0600854
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600855 # Run our meagre tests
Simon Glass7640b162022-07-30 20:57:09 -0600856 if args.test:
857 ret_code = run_tests(args.name, args.processes)
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600858 return ret_code
Simon Glass7640b162022-07-30 20:57:09 -0600859 if args.test_coverage:
860 run_test_coverage(args.build_dir)
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600861 return 0
Simon Glass2ba98752018-07-06 10:27:24 -0600862
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600863if __name__ == '__main__':
864 sys.exit(main())