blob: ebc5297b5067acdfb800c83e043e6a9ad29bcff4 [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 Glass4583c002023-02-23 18:18:04 -070033from u_boot_pylib import test_util
34from u_boot_pylib 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)
Simon Glasse316fba2023-02-13 08:56:34 -0700135 self.assertEqual(['boolval', 'bootph-all', 'bytearray', 'byteval',
136 'compatible', 'int64val', 'intarray', 'intval',
137 'longbytearray', 'maybe-empty-int', 'notstring',
138 'stringarray', 'stringval', ],
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 Glass4df457b2023-07-18 07:24:02 -0600309 def test_copy_node(self):
310 """Test copy_node() function"""
311 def do_copy_checks(dtb, dst, expect_none):
312 self.assertEqual(
313 ['/dest/base', '/dest/first@0', '/dest/existing'],
314 [n.path for n in dst.subnodes])
315
316 chk = dtb.GetNode('/dest/base')
317 self.assertTrue(chk)
318 self.assertEqual(
319 {'compatible', 'bootph-all', '#address-cells', '#size-cells'},
320 chk.props.keys())
321
322 # Check the first property
323 prop = chk.props['bootph-all']
324 self.assertEqual('bootph-all', prop.name)
325 self.assertEqual(True, prop.value)
326 self.assertEqual(chk.path, prop._node.path)
327
328 # Check the second property
329 prop2 = chk.props['compatible']
330 self.assertEqual('compatible', prop2.name)
331 self.assertEqual('sandbox,i2c', prop2.value)
332 self.assertEqual(chk.path, prop2._node.path)
333
334 base = chk.FindNode('base')
335 self.assertTrue(chk)
336
337 first = dtb.GetNode('/dest/base/first@0')
338 self.assertTrue(first)
339 over = dtb.GetNode('/dest/base/over')
340 self.assertTrue(over)
341
342 # Make sure that the phandle for 'over' is not copied
343 self.assertNotIn('phandle', over.props.keys())
344
345 second = dtb.GetNode('/dest/base/second')
346 self.assertTrue(second)
347 self.assertEqual([over.name, first.name, second.name],
348 [n.name for n in chk.subnodes])
349 self.assertEqual(chk, over.parent)
350 self.assertEqual(
351 {'bootph-all', 'compatible', 'reg', 'low-power'},
352 over.props.keys())
353
354 if expect_none:
355 self.assertIsNone(prop._offset)
356 self.assertIsNone(prop2._offset)
357 self.assertIsNone(over._offset)
358 else:
359 self.assertTrue(prop._offset)
360 self.assertTrue(prop2._offset)
361 self.assertTrue(over._offset)
362
363 # Now check ordering of the subnodes
364 self.assertEqual(
365 ['second1', 'second2', 'second3', 'second4'],
366 [n.name for n in second.subnodes])
367
368 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_copy.dts'))
369 tmpl = dtb.GetNode('/base')
370 dst = dtb.GetNode('/dest')
371 dst.copy_node(tmpl)
372
373 do_copy_checks(dtb, dst, expect_none=True)
374
375 dtb.Sync(auto_resize=True)
376
377 # Now check that the FDT looks correct
378 new_dtb = fdt.Fdt.FromData(dtb.GetContents())
379 new_dtb.Scan()
380 dst = new_dtb.GetNode('/dest')
381 do_copy_checks(new_dtb, dst, expect_none=False)
382
Simon Glass2ba98752018-07-06 10:27:24 -0600383
384class TestProp(unittest.TestCase):
385 """Test operation of the Prop class"""
386
387 @classmethod
388 def setUpClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700389 tools.prepare_output_dir(None)
Simon Glass2ba98752018-07-06 10:27:24 -0600390
391 @classmethod
392 def tearDownClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700393 tools.finalise_output_dir()
Simon Glass2ba98752018-07-06 10:27:24 -0600394
395 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700396 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -0600397 self.node = self.dtb.GetNode('/spl-test')
398 self.fdt = self.dtb.GetFdtObj()
399
Simon Glass5d1637a2022-07-30 20:57:10 -0600400 def test_missing_node(self):
401 """Test GetNode() when the node is missing"""
Simon Glassb9066ff2018-07-06 10:27:30 -0600402 self.assertEqual(None, self.dtb.GetNode('missing'))
403
Simon Glass5d1637a2022-07-30 20:57:10 -0600404 def test_phandle(self):
405 """Test GetNode() on a phandle"""
Simon Glassdff51a52021-02-03 06:00:56 -0700406 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass760b7172018-07-06 10:27:31 -0600407 node = dtb.GetNode('/phandle-source2')
408 prop = node.props['clocks']
409 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600410
Simon Glass5d1637a2022-07-30 20:57:10 -0600411 def _convert_prop(self, prop_name):
Simon Glass2a2d91d2018-07-06 10:27:28 -0600412 """Helper function to look up a property in self.node and return it
413
414 Args:
Simon Glass5d1637a2022-07-30 20:57:10 -0600415 str: Property name to find
Simon Glass2a2d91d2018-07-06 10:27:28 -0600416
Simon Glass5d1637a2022-07-30 20:57:10 -0600417 Returns:
418 fdt.Prop: object for this property
Simon Glass2a2d91d2018-07-06 10:27:28 -0600419 """
Simon Glass5d1637a2022-07-30 20:57:10 -0600420 prop = self.fdt.getprop(self.node.Offset(), prop_name)
421 return fdt.Prop(self.node, -1, prop_name, prop)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600422
Simon Glass5d1637a2022-07-30 20:57:10 -0600423 def test_make_prop(self):
Simon Glass2a2d91d2018-07-06 10:27:28 -0600424 """Test we can convert all the the types that are supported"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600425 prop = self._convert_prop('boolval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700426 self.assertEqual(Type.BOOL, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600427 self.assertEqual(True, prop.value)
428
Simon Glass5d1637a2022-07-30 20:57:10 -0600429 prop = self._convert_prop('intval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700430 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600431 self.assertEqual(1, fdt32_to_cpu(prop.value))
432
Simon Glass5d1637a2022-07-30 20:57:10 -0600433 prop = self._convert_prop('int64val')
Simon Glassd866e622021-11-23 11:03:39 -0700434 self.assertEqual(Type.INT, prop.type)
435 self.assertEqual(0x123456789abcdef0, fdt64_to_cpu(prop.value))
436
Simon Glass5d1637a2022-07-30 20:57:10 -0600437 prop = self._convert_prop('intarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700438 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600439 val = [fdt32_to_cpu(val) for val in prop.value]
440 self.assertEqual([2, 3, 4], val)
441
Simon Glass5d1637a2022-07-30 20:57:10 -0600442 prop = self._convert_prop('byteval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700443 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600444 self.assertEqual(5, ord(prop.value))
445
Simon Glass5d1637a2022-07-30 20:57:10 -0600446 prop = self._convert_prop('longbytearray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700447 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600448 val = [ord(val) for val in prop.value]
449 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
450
Simon Glass5d1637a2022-07-30 20:57:10 -0600451 prop = self._convert_prop('stringval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700452 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600453 self.assertEqual('message', prop.value)
454
Simon Glass5d1637a2022-07-30 20:57:10 -0600455 prop = self._convert_prop('stringarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700456 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600457 self.assertEqual(['multi-word', 'message'], prop.value)
458
Simon Glass5d1637a2022-07-30 20:57:10 -0600459 prop = self._convert_prop('notstring')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700460 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600461 val = [ord(val) for val in prop.value]
462 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
463
Simon Glass5d1637a2022-07-30 20:57:10 -0600464 def test_get_empty(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600465 """Tests the GetEmpty() function for the various supported types"""
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700466 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
467 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
Simon Glassc1aa66e2022-01-29 14:14:04 -0700468 self.assertEqual(tools.get_bytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700469 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass2ba98752018-07-06 10:27:24 -0600470
Simon Glass5d1637a2022-07-30 20:57:10 -0600471 def test_get_offset(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600472 """Test we can get the offset of a property"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600473 prop, value = _get_property_value(self.dtb, self.node, 'longbytearray')
Simon Glassf9b88b32018-07-06 10:27:29 -0600474 self.assertEqual(prop.value, value)
Simon Glass2ba98752018-07-06 10:27:24 -0600475
Simon Glass5d1637a2022-07-30 20:57:10 -0600476 def test_widen(self):
Simon Glass2ba98752018-07-06 10:27:24 -0600477 """Test widening of values"""
478 node2 = self.dtb.GetNode('/spl-test2')
Simon Glasse144caf2020-10-03 11:31:27 -0600479 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass2ba98752018-07-06 10:27:24 -0600480 prop = self.node.props['intval']
481
482 # No action
483 prop2 = node2.props['intval']
484 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700485 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600486 self.assertEqual(1, fdt32_to_cpu(prop.value))
487
Simon Glassca044942021-07-28 19:23:10 -0600488 # Convert single value to array
Simon Glass2ba98752018-07-06 10:27:24 -0600489 prop2 = self.node.props['intarray']
490 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700491 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600492 self.assertTrue(isinstance(prop.value, list))
493
494 # A 4-byte array looks like a single integer. When widened by a longer
495 # byte array, it should turn into an array.
496 prop = self.node.props['longbytearray']
497 prop2 = node2.props['longbytearray']
Simon Glasse144caf2020-10-03 11:31:27 -0600498 prop3 = node3.props['longbytearray']
Simon Glass2ba98752018-07-06 10:27:24 -0600499 self.assertFalse(isinstance(prop2.value, list))
500 self.assertEqual(4, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600501 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600502 prop2.Widen(prop)
503 self.assertTrue(isinstance(prop2.value, list))
504 self.assertEqual(9, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600505 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
506 '\0', '\0', '\0', '\0'], prop2.value)
507 prop3.Widen(prop)
508 self.assertTrue(isinstance(prop3.value, list))
509 self.assertEqual(9, len(prop3.value))
510 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
511 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600512
Simon Glass5d1637a2022-07-30 20:57:10 -0600513 def test_widen_more(self):
514 """More tests of widening values"""
515 node2 = self.dtb.GetNode('/spl-test2')
516 node3 = self.dtb.GetNode('/spl-test3')
517 prop = self.node.props['intval']
518
519 # Test widening a single string into a string array
Simon Glass2ba98752018-07-06 10:27:24 -0600520 prop = self.node.props['stringval']
521 prop2 = node2.props['stringarray']
522 self.assertFalse(isinstance(prop.value, list))
523 self.assertEqual(7, len(prop.value))
524 prop.Widen(prop2)
525 self.assertTrue(isinstance(prop.value, list))
526 self.assertEqual(3, len(prop.value))
527
528 # Enlarging an existing array
529 prop = self.node.props['stringarray']
530 prop2 = node2.props['stringarray']
531 self.assertTrue(isinstance(prop.value, list))
532 self.assertEqual(2, len(prop.value))
533 prop.Widen(prop2)
534 self.assertTrue(isinstance(prop.value, list))
535 self.assertEqual(3, len(prop.value))
536
Simon Glassca044942021-07-28 19:23:10 -0600537 # Widen an array of ints with an int (should do nothing)
538 prop = self.node.props['intarray']
Simon Glasse679f392021-08-02 07:37:54 -0600539 prop2 = node2.props['intval']
Simon Glassca044942021-07-28 19:23:10 -0600540 self.assertEqual(Type.INT, prop.type)
541 self.assertEqual(3, len(prop.value))
542 prop.Widen(prop2)
543 self.assertEqual(Type.INT, prop.type)
544 self.assertEqual(3, len(prop.value))
545
Simon Glasseec44c72021-07-28 19:23:11 -0600546 # Widen an empty bool to an int
547 prop = self.node.props['maybe-empty-int']
548 prop3 = node3.props['maybe-empty-int']
549 self.assertEqual(Type.BOOL, prop.type)
550 self.assertEqual(True, prop.value)
551 self.assertEqual(Type.INT, prop3.type)
552 self.assertFalse(isinstance(prop.value, list))
553 self.assertEqual(4, len(prop3.value))
554 prop.Widen(prop3)
555 self.assertEqual(Type.INT, prop.type)
556 self.assertTrue(isinstance(prop.value, list))
557 self.assertEqual(1, len(prop.value))
558
Simon Glass5d1637a2022-07-30 20:57:10 -0600559 def test_add(self):
Simon Glass116adec2018-07-06 10:27:38 -0600560 """Test adding properties"""
561 self.fdt.pack()
562 # This function should automatically expand the device tree
563 self.node.AddZeroProp('one')
564 self.node.AddZeroProp('two')
565 self.node.AddZeroProp('three')
Simon Glassfa80c252018-09-14 04:57:13 -0600566 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600567
568 # Updating existing properties should be OK, since the device-tree size
569 # does not change
570 self.fdt.pack()
571 self.node.SetInt('one', 1)
572 self.node.SetInt('two', 2)
573 self.node.SetInt('three', 3)
Simon Glassfa80c252018-09-14 04:57:13 -0600574 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600575
576 # This should fail since it would need to increase the device-tree size
Simon Glassfa80c252018-09-14 04:57:13 -0600577 self.node.AddZeroProp('four')
Simon Glass5d1637a2022-07-30 20:57:10 -0600578 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glassfa80c252018-09-14 04:57:13 -0600579 self.dtb.Sync(auto_resize=False)
Simon Glass5d1637a2022-07-30 20:57:10 -0600580 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glass64349612018-09-14 04:57:16 -0600581 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600582
Simon Glass5d1637a2022-07-30 20:57:10 -0600583 def test_add_more(self):
Simon Glass64349612018-09-14 04:57:16 -0600584 """Test various other methods for adding and setting properties"""
585 self.node.AddZeroProp('one')
586 self.dtb.Sync(auto_resize=True)
587 data = self.fdt.getprop(self.node.Offset(), 'one')
588 self.assertEqual(0, fdt32_to_cpu(data))
589
590 self.node.SetInt('one', 1)
591 self.dtb.Sync(auto_resize=False)
592 data = self.fdt.getprop(self.node.Offset(), 'one')
593 self.assertEqual(1, fdt32_to_cpu(data))
594
Simon Glass6eb99322021-01-06 21:35:18 -0700595 val = 1234
596 self.node.AddInt('integer', val)
597 self.dtb.Sync(auto_resize=True)
598 data = self.fdt.getprop(self.node.Offset(), 'integer')
599 self.assertEqual(val, fdt32_to_cpu(data))
600
Simon Glass64349612018-09-14 04:57:16 -0600601 val = '123' + chr(0) + '456'
602 self.node.AddString('string', val)
603 self.dtb.Sync(auto_resize=True)
604 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700605 self.assertEqual(tools.to_bytes(val) + b'\0', data)
Simon Glass64349612018-09-14 04:57:16 -0600606
607 self.fdt.pack()
608 self.node.SetString('string', val + 'x')
Simon Glass5d1637a2022-07-30 20:57:10 -0600609 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glass64349612018-09-14 04:57:16 -0600610 self.dtb.Sync(auto_resize=False)
Simon Glass5d1637a2022-07-30 20:57:10 -0600611 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glass64349612018-09-14 04:57:16 -0600612 self.node.SetString('string', val[:-1])
613
614 prop = self.node.props['string']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700615 prop.SetData(tools.to_bytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600616 self.dtb.Sync(auto_resize=False)
617 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700618 self.assertEqual(tools.to_bytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600619
620 self.node.AddEmptyProp('empty', 5)
621 self.dtb.Sync(auto_resize=True)
622 prop = self.node.props['empty']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700623 prop.SetData(tools.to_bytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600624 self.dtb.Sync(auto_resize=False)
625 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700626 self.assertEqual(tools.to_bytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600627
Simon Glassf6b64812019-05-17 22:00:36 -0600628 self.node.SetData('empty', b'123')
629 self.assertEqual(b'123', prop.bytes)
Simon Glass64349612018-09-14 04:57:16 -0600630
Simon Glassc0639172020-07-09 18:39:44 -0600631 # Trying adding a lot of data at once
Simon Glassc1aa66e2022-01-29 14:14:04 -0700632 self.node.AddData('data', tools.get_bytes(65, 20000))
Simon Glassc0639172020-07-09 18:39:44 -0600633 self.dtb.Sync(auto_resize=True)
634
Simon Glassbc116022022-02-08 11:49:50 -0700635 def test_string_list(self):
636 """Test adding string-list property to a node"""
637 val = ['123', '456']
638 self.node.AddStringList('stringlist', val)
639 self.dtb.Sync(auto_resize=True)
640 data = self.fdt.getprop(self.node.Offset(), 'stringlist')
641 self.assertEqual(b'123\x00456\0', data)
642
Simon Glass0ded4d42022-03-05 20:18:56 -0700643 val = []
644 self.node.AddStringList('stringlist', val)
645 self.dtb.Sync(auto_resize=True)
646 data = self.fdt.getprop(self.node.Offset(), 'stringlist')
647 self.assertEqual(b'', data)
648
Simon Glassa30c39f2022-02-08 11:49:51 -0700649 def test_delete_node(self):
650 """Test deleting a node"""
651 old_offset = self.fdt.path_offset('/spl-test')
652 self.assertGreater(old_offset, 0)
653 self.node.Delete()
654 self.dtb.Sync()
655 new_offset = self.fdt.path_offset('/spl-test', libfdt.QUIET_NOTFOUND)
656 self.assertEqual(-libfdt.NOTFOUND, new_offset)
657
Simon Glass5d1637a2022-07-30 20:57:10 -0600658 def test_from_data(self):
659 """Test creating an FDT from data"""
Simon Glass746aee32018-09-14 04:57:17 -0600660 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
661 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
662
663 self.node.AddEmptyProp('empty', 5)
664 self.dtb.Sync(auto_resize=True)
665 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
666
Simon Glass5d1637a2022-07-30 20:57:10 -0600667 def test_missing_set_int(self):
Simon Glassd9dad102019-07-20 12:23:37 -0600668 """Test handling of a missing property with SetInt"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600669 with self.assertRaises(ValueError) as exc:
Simon Glassd9dad102019-07-20 12:23:37 -0600670 self.node.SetInt('one', 1)
671 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600672 str(exc.exception))
Simon Glassd9dad102019-07-20 12:23:37 -0600673
Simon Glass5d1637a2022-07-30 20:57:10 -0600674 def test_missing_set_data(self):
Simon Glassd9dad102019-07-20 12:23:37 -0600675 """Test handling of a missing property with SetData"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600676 with self.assertRaises(ValueError) as exc:
Simon Glassd9dad102019-07-20 12:23:37 -0600677 self.node.SetData('one', b'data')
678 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600679 str(exc.exception))
Simon Glassd9dad102019-07-20 12:23:37 -0600680
Simon Glass5d1637a2022-07-30 20:57:10 -0600681 def test_missing_set_string(self):
Simon Glassd9dad102019-07-20 12:23:37 -0600682 """Test handling of a missing property with SetString"""
Simon Glass5d1637a2022-07-30 20:57:10 -0600683 with self.assertRaises(ValueError) as exc:
Simon Glassd9dad102019-07-20 12:23:37 -0600684 self.node.SetString('one', 1)
685 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass5d1637a2022-07-30 20:57:10 -0600686 str(exc.exception))
Simon Glassd9dad102019-07-20 12:23:37 -0600687
Simon Glass5d1637a2022-07-30 20:57:10 -0600688 def test_get_filename(self):
Simon Glassf6e02492019-07-20 12:24:08 -0600689 """Test the dtb filename can be provided"""
Simon Glassc1aa66e2022-01-29 14:14:04 -0700690 self.assertEqual(tools.get_output_filename('source.dtb'),
Simon Glassf6e02492019-07-20 12:24:08 -0600691 self.dtb.GetFilename())
692
Simon Glass2ba98752018-07-06 10:27:24 -0600693
Simon Glass2a2d91d2018-07-06 10:27:28 -0600694class TestFdtUtil(unittest.TestCase):
695 """Tests for the fdt_util module
696
697 This module will likely be mostly replaced at some point, once upstream
698 libfdt has better Python support. For now, this provides tests for current
699 functionality.
700 """
701 @classmethod
702 def setUpClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700703 tools.prepare_output_dir(None)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600704
Simon Glasse0e62752018-10-01 21:12:41 -0600705 @classmethod
706 def tearDownClass(cls):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700707 tools.finalise_output_dir()
Simon Glasse0e62752018-10-01 21:12:41 -0600708
Simon Glass2a2d91d2018-07-06 10:27:28 -0600709 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700710 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600711 self.node = self.dtb.GetNode('/spl-test')
712
Simon Glass5d1637a2022-07-30 20:57:10 -0600713 def test_get_int(self):
714 """Test getting an int from a node"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600715 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
716 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
717
Simon Glass5d1637a2022-07-30 20:57:10 -0600718 with self.assertRaises(ValueError) as exc:
Simon Glassd866e622021-11-23 11:03:39 -0700719 fdt_util.GetInt(self.node, 'intarray')
Simon Glass2a2d91d2018-07-06 10:27:28 -0600720 self.assertIn("property 'intarray' has list value: expecting a single "
Simon Glass5d1637a2022-07-30 20:57:10 -0600721 'integer', str(exc.exception))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600722
Simon Glass5d1637a2022-07-30 20:57:10 -0600723 def test_get_int64(self):
724 """Test getting a 64-bit int from a node"""
Simon Glassd866e622021-11-23 11:03:39 -0700725 self.assertEqual(0x123456789abcdef0,
726 fdt_util.GetInt64(self.node, 'int64val'))
727 self.assertEqual(3, fdt_util.GetInt64(self.node, 'missing', 3))
728
Simon Glass5d1637a2022-07-30 20:57:10 -0600729 with self.assertRaises(ValueError) as exc:
Simon Glassd866e622021-11-23 11:03:39 -0700730 fdt_util.GetInt64(self.node, 'intarray')
731 self.assertIn(
732 "property 'intarray' should be a list with 2 items for 64-bit values",
Simon Glass5d1637a2022-07-30 20:57:10 -0600733 str(exc.exception))
Simon Glassd866e622021-11-23 11:03:39 -0700734
Simon Glass5d1637a2022-07-30 20:57:10 -0600735 def test_get_string(self):
736 """Test getting a string from a node"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600737 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
738 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
739 'test'))
Simon Glass0ded4d42022-03-05 20:18:56 -0700740 self.assertEqual('', fdt_util.GetString(self.node, 'boolval'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600741
Simon Glass5d1637a2022-07-30 20:57:10 -0600742 with self.assertRaises(ValueError) as exc:
Simon Glass2a2d91d2018-07-06 10:27:28 -0600743 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
744 self.assertIn("property 'stringarray' has list value: expecting a "
Simon Glass5d1637a2022-07-30 20:57:10 -0600745 'single string', str(exc.exception))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600746
Simon Glass5d1637a2022-07-30 20:57:10 -0600747 def test_get_string_list(self):
748 """Test getting a string list from a node"""
Simon Glass1b5a5332021-11-23 21:09:51 -0700749 self.assertEqual(['message'],
750 fdt_util.GetStringList(self.node, 'stringval'))
751 self.assertEqual(
752 ['multi-word', 'message'],
753 fdt_util.GetStringList(self.node, 'stringarray'))
754 self.assertEqual(['test'],
755 fdt_util.GetStringList(self.node, 'missing', ['test']))
Simon Glass0ded4d42022-03-05 20:18:56 -0700756 self.assertEqual([], fdt_util.GetStringList(self.node, 'boolval'))
Simon Glass1b5a5332021-11-23 21:09:51 -0700757
Simon Glass5d1637a2022-07-30 20:57:10 -0600758 def test_get_args(self):
759 """Test getting arguments from a node"""
Simon Glass7e4b66a2022-02-08 11:49:53 -0700760 node = self.dtb.GetNode('/orig-node')
761 self.assertEqual(['message'], fdt_util.GetArgs(self.node, 'stringval'))
762 self.assertEqual(
763 ['multi-word', 'message'],
764 fdt_util.GetArgs(self.node, 'stringarray'))
765 self.assertEqual([], fdt_util.GetArgs(self.node, 'boolval'))
Simon Glass61012532022-03-05 20:18:52 -0700766 self.assertEqual(['-n first', 'second', '-p', '123,456', '-x'],
Simon Glass7e4b66a2022-02-08 11:49:53 -0700767 fdt_util.GetArgs(node, 'args'))
Simon Glass61012532022-03-05 20:18:52 -0700768 self.assertEqual(['a space', 'there'],
769 fdt_util.GetArgs(node, 'args2'))
770 self.assertEqual(['-n', 'first', 'second', '-p', '123,456', '-x'],
771 fdt_util.GetArgs(node, 'args3'))
Simon Glass7e4b66a2022-02-08 11:49:53 -0700772 with self.assertRaises(ValueError) as exc:
773 fdt_util.GetArgs(self.node, 'missing')
774 self.assertIn(
775 "Node '/spl-test': Expected property 'missing'",
776 str(exc.exception))
777
Simon Glass5d1637a2022-07-30 20:57:10 -0600778 def test_get_bool(self):
779 """Test getting a bool from a node"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600780 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
781 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
782 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
783 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
784
Simon Glass5d1637a2022-07-30 20:57:10 -0600785 def test_get_byte(self):
786 """Test getting a byte from a node"""
Simon Glass3af8e492018-07-17 13:25:40 -0600787 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
788 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
789
Simon Glass5d1637a2022-07-30 20:57:10 -0600790 with self.assertRaises(ValueError) as exc:
Simon Glass3af8e492018-07-17 13:25:40 -0600791 fdt_util.GetByte(self.node, 'longbytearray')
792 self.assertIn("property 'longbytearray' has list value: expecting a "
Simon Glass5d1637a2022-07-30 20:57:10 -0600793 'single byte', str(exc.exception))
Simon Glass3af8e492018-07-17 13:25:40 -0600794
Simon Glass5d1637a2022-07-30 20:57:10 -0600795 with self.assertRaises(ValueError) as exc:
Simon Glass3af8e492018-07-17 13:25:40 -0600796 fdt_util.GetByte(self.node, 'intval')
797 self.assertIn("property 'intval' has length 4, expecting 1",
Simon Glass5d1637a2022-07-30 20:57:10 -0600798 str(exc.exception))
Simon Glass3af8e492018-07-17 13:25:40 -0600799
Simon Glass5d1637a2022-07-30 20:57:10 -0600800 def test_get_bytes(self):
801 """Test getting multiple bytes from a node"""
Simon Glass40b4d642021-11-23 11:03:40 -0700802 self.assertEqual(bytes([5]), fdt_util.GetBytes(self.node, 'byteval', 1))
803 self.assertEqual(None, fdt_util.GetBytes(self.node, 'missing', 3))
804 self.assertEqual(
805 bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3, bytes([3])))
806
Simon Glass5d1637a2022-07-30 20:57:10 -0600807 with self.assertRaises(ValueError) as exc:
Simon Glass40b4d642021-11-23 11:03:40 -0700808 fdt_util.GetBytes(self.node, 'longbytearray', 7)
809 self.assertIn(
810 "Node 'spl-test' property 'longbytearray' has length 9, expecting 7",
Simon Glass5d1637a2022-07-30 20:57:10 -0600811 str(exc.exception))
Simon Glass40b4d642021-11-23 11:03:40 -0700812
813 self.assertEqual(
814 bytes([0, 0, 0, 1]), fdt_util.GetBytes(self.node, 'intval', 4))
815 self.assertEqual(
816 bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3, bytes([3])))
817
Simon Glass5d1637a2022-07-30 20:57:10 -0600818 def test_get_phandle_list(self):
819 """Test getting a list of phandles from a node"""
Simon Glassdff51a52021-02-03 06:00:56 -0700820 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass94a7c602018-07-17 13:25:46 -0600821 node = dtb.GetNode('/phandle-source2')
822 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
823 node = dtb.GetNode('/phandle-source')
824 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
825 fdt_util.GetPhandleList(node, 'clocks'))
826 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
827
Simon Glass5d1637a2022-07-30 20:57:10 -0600828 def test_get_data_type(self):
829 """Test getting a value of a particular type from a node"""
Simon Glass53af22a2018-07-17 13:25:32 -0600830 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
831 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
832 str))
Simon Glass5d1637a2022-07-30 20:57:10 -0600833 with self.assertRaises(ValueError):
Simon Glass53af22a2018-07-17 13:25:32 -0600834 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
835 bool))
Simon Glass5d1637a2022-07-30 20:57:10 -0600836 def test_fdt_cells_to_cpu(self):
837 """Test getting cells with the correct endianness"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600838 val = self.node.props['intarray'].value
839 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
840 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
841
Simon Glassdff51a52021-02-03 06:00:56 -0700842 dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
Simon Glasse66d3182019-05-17 22:00:40 -0600843 node1 = dtb2.GetNode('/test1')
844 val = node1.props['reg'].value
Simon Glass2a2d91d2018-07-06 10:27:28 -0600845 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
846
Simon Glasse66d3182019-05-17 22:00:40 -0600847 node2 = dtb2.GetNode('/test2')
848 val = node2.props['reg'].value
849 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
850 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
851 2))
852 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
853
Simon Glass5d1637a2022-07-30 20:57:10 -0600854 def test_ensure_compiled(self):
Simon Glassa004f292019-07-20 12:23:49 -0600855 """Test a degenerate case of this function (file already compiled)"""
Simon Glassdff51a52021-02-03 06:00:56 -0700856 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600857 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
858
Simon Glass5d1637a2022-07-30 20:57:10 -0600859 def test_ensure_compiled_tmpdir(self):
Simon Glassa004f292019-07-20 12:23:49 -0600860 """Test providing a temporary directory"""
Heinrich Schuchardtd0d0e772023-04-20 20:03:43 +0200861 old_outdir = tools.outdir
Simon Glassa004f292019-07-20 12:23:49 -0600862 try:
Simon Glassa004f292019-07-20 12:23:49 -0600863 tools.outdir= None
864 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
Simon Glassdff51a52021-02-03 06:00:56 -0700865 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
Simon Glassa004f292019-07-20 12:23:49 -0600866 tmpdir)
867 self.assertEqual(tmpdir, os.path.dirname(dtb))
868 shutil.rmtree(tmpdir)
869 finally:
Heinrich Schuchardtd0d0e772023-04-20 20:03:43 +0200870 tools.outdir = old_outdir
Simon Glassa004f292019-07-20 12:23:49 -0600871
Simon Glass8f5afe22023-01-11 16:10:18 -0700872 def test_get_phandle_name_offset(self):
873 val = fdt_util.GetPhandleNameOffset(self.node, 'missing')
874 self.assertIsNone(val)
875
876 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
877 node = dtb.GetNode('/phandle-source')
878 node, name, offset = fdt_util.GetPhandleNameOffset(node,
879 'phandle-name-offset')
880 self.assertEqual('phandle3-target', node.name)
881 self.assertEqual('fred', name)
882 self.assertEqual(123, offset)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600883
Simon Glass25980792022-07-30 20:57:05 -0600884def run_test_coverage(build_dir):
885 """Run the tests and check that we get 100% coverage
886
887 Args:
888 build_dir (str): Directory containing the build output
889 """
Simon Glass5e2ab402022-01-29 14:14:14 -0700890 test_util.run_test_coverage('tools/dtoc/test_fdt.py', None,
Simon Glass4583c002023-02-23 18:18:04 -0700891 ['tools/patman/*.py', 'tools/u_boot_pylib/*', '*test_fdt.py'],
892 build_dir)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600893
894
Simon Glass7640b162022-07-30 20:57:09 -0600895def run_tests(names, processes):
Simon Glass2ba98752018-07-06 10:27:24 -0600896 """Run all the test we have for the fdt model
897
898 Args:
Simon Glass7640b162022-07-30 20:57:09 -0600899 names (list of str): List of test names provided. Only the first is used
Simon Glassb26dd962022-07-30 20:57:06 -0600900 processes (int): Number of processes to use (None means as many as there
901 are CPUs on the system. This must be set to 1 when running under
902 the python3-coverage tool
Simon Glass42ae3632022-03-18 18:01:50 -0600903
904 Returns:
Simon Glassb26dd962022-07-30 20:57:06 -0600905 int: Return code, 0 on success
Simon Glass2ba98752018-07-06 10:27:24 -0600906 """
Simon Glass7640b162022-07-30 20:57:09 -0600907 test_name = names[0] if names else None
Alper Nebi Yasakd8318fe2022-04-02 20:06:06 +0300908 result = test_util.run_test_suites(
Simon Glassad744222022-07-30 20:57:07 -0600909 'test_fdt', False, False, False, processes, test_name, None,
Simon Glass42ae3632022-03-18 18:01:50 -0600910 [TestFdt, TestNode, TestProp, TestFdtUtil])
Simon Glass2ba98752018-07-06 10:27:24 -0600911
Alper Nebi Yasakd8318fe2022-04-02 20:06:06 +0300912 return (0 if result.wasSuccessful() else 1)
913
Simon Glass2ba98752018-07-06 10:27:24 -0600914
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600915def main():
916 """Main program for this tool"""
Simon Glass7640b162022-07-30 20:57:09 -0600917 parser = ArgumentParser()
918 parser.add_argument('-B', '--build-dir', type=str, default='b',
919 help='Directory containing the build output')
920 parser.add_argument('-P', '--processes', type=int,
921 help='set number of processes to use for running tests')
922 parser.add_argument('-t', '--test', action='store_true', dest='test',
923 default=False, help='run tests')
924 parser.add_argument('-T', '--test-coverage', action='store_true',
925 default=False,
926 help='run tests and check for 100% coverage')
927 parser.add_argument('name', nargs='*')
928 args = parser.parse_args()
Simon Glass2ba98752018-07-06 10:27:24 -0600929
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600930 # Run our meagre tests
Simon Glass7640b162022-07-30 20:57:09 -0600931 if args.test:
932 ret_code = run_tests(args.name, args.processes)
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600933 return ret_code
Simon Glass7640b162022-07-30 20:57:09 -0600934 if args.test_coverage:
935 run_test_coverage(args.build_dir)
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600936 return 0
Simon Glass2ba98752018-07-06 10:27:24 -0600937
Simon Glassa8ad9aa2022-07-30 20:57:08 -0600938if __name__ == '__main__':
939 sys.exit(main())