blob: 3e54694eec9ffa0958e1ab217e9d32e025e97b58 [file] [log] [blame]
Simon Glassfc017822019-10-31 07:42:54 -06001#!/usr/bin/env python3
Simon Glass0ed50752018-07-06 10:27:24 -06002# SPDX-License-Identifier: GPL-2.0+
Simon Glass04afdfe2022-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 Glass0ed50752018-07-06 10:27:24 -06009
Simon Glass882f6322022-07-30 20:57:09 -060010from argparse import ArgumentParser
Simon Glass0ed50752018-07-06 10:27:24 -060011import os
Simon Glassb8d2daa2019-07-20 12:23:49 -060012import shutil
Simon Glass0ed50752018-07-06 10:27:24 -060013import sys
Simon Glassb8d2daa2019-07-20 12:23:49 -060014import tempfile
Simon Glass0ed50752018-07-06 10:27:24 -060015import unittest
16
17# Bring in the patman libraries
18our_path = os.path.dirname(os.path.realpath(__file__))
Simon Glass42143162020-04-17 18:09:05 -060019sys.path.insert(1, os.path.join(our_path, '..'))
Simon Glass0ed50752018-07-06 10:27:24 -060020
Simon Glass7e10f8a2021-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 Glass04afdfe2022-07-30 20:57:10 -060027#pylint: disable=wrong-import-position
Simon Glassa997ea52020-04-17 18:09:04 -060028from dtoc import fdt
29from dtoc import fdt_util
Simon Glass3b55e3f2021-11-23 11:03:39 -070030from dtoc.fdt_util import fdt32_to_cpu, fdt64_to_cpu
Simon Glass2b160072022-02-11 13:23:20 -070031from dtoc.fdt import Type, BytesToValue
Simon Glass0ed50752018-07-06 10:27:24 -060032import libfdt
Simon Glass131444f2023-02-23 18:18:04 -070033from u_boot_pylib import test_util
34from u_boot_pylib import tools
Simon Glass0ed50752018-07-06 10:27:24 -060035
Simon Glass04afdfe2022-07-30 20:57:10 -060036#pylint: disable=protected-access
37
38def _get_property_value(dtb, node, prop_name):
Simon Glass4df8a0c2018-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 Glass632b84c2020-11-08 20:36:20 -070059 return prop, [chr(x) for x in data]
Simon Glass4df8a0c2018-07-06 10:27:29 -060060
Simon Glass4f4b2402021-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 Glass4df8a0c2018-07-06 10:27:29 -060072
Simon Glass0ed50752018-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 Glass80025522022-01-29 14:14:04 -070081 tools.prepare_output_dir(None)
Simon Glass0ed50752018-07-06 10:27:24 -060082
83 @classmethod
84 def tearDownClass(cls):
Simon Glass80025522022-01-29 14:14:04 -070085 tools.finalise_output_dir()
Simon Glass0ed50752018-07-06 10:27:24 -060086
87 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -070088 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass0ed50752018-07-06 10:27:24 -060089
Simon Glass04afdfe2022-07-30 20:57:10 -060090 def test_fdt(self):
Simon Glass0ed50752018-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 Glass04afdfe2022-07-30 20:57:10 -060096 def test_get_node(self):
Simon Glass0ed50752018-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 Glass3b9a8292019-07-20 12:23:39 -0600100
Simon Glass0ed50752018-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 Glass9c526332018-07-06 10:27:28 -0600104 self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
Simon Glass0ed50752018-07-06 10:27:24 -0600105
Simon Glass3b9a8292019-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 Glass04afdfe2022-07-30 20:57:10 -0600110 def test_flush(self):
Simon Glass0ed50752018-07-06 10:27:24 -0600111 """Check that we can flush the device tree out to its file"""
112 fname = self.dtb._fname
Simon Glass04afdfe2022-07-30 20:57:10 -0600113 with open(fname, 'rb') as inf:
114 inf.read()
Simon Glass0ed50752018-07-06 10:27:24 -0600115 os.remove(fname)
116 with self.assertRaises(IOError):
Simon Glass04afdfe2022-07-30 20:57:10 -0600117 with open(fname, 'rb'):
118 pass
Simon Glass0ed50752018-07-06 10:27:24 -0600119 self.dtb.Flush()
Simon Glass04afdfe2022-07-30 20:57:10 -0600120 with open(fname, 'rb') as inf:
121 inf.read()
Simon Glass0ed50752018-07-06 10:27:24 -0600122
Simon Glass04afdfe2022-07-30 20:57:10 -0600123 def test_pack(self):
Simon Glass0ed50752018-07-06 10:27:24 -0600124 """Test that packing a device tree works"""
125 self.dtb.Pack()
126
Simon Glass04afdfe2022-07-30 20:57:10 -0600127 def test_get_fdt_raw(self):
Simon Glass0ed50752018-07-06 10:27:24 -0600128 """Tetst that we can access the raw device-tree data"""
Simon Glass2b160072022-02-11 13:23:20 -0700129 self.assertTrue(isinstance(self.dtb.GetContents(), bytes))
Simon Glass0ed50752018-07-06 10:27:24 -0600130
Simon Glass04afdfe2022-07-30 20:57:10 -0600131 def test_get_props(self):
Simon Glass0ed50752018-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 Glassfc1aa352023-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 Glass0ed50752018-07-06 10:27:24 -0600139 sorted(props.keys()))
140
Simon Glass04afdfe2022-07-30 20:57:10 -0600141 def test_check_error(self):
Simon Glass0ed50752018-07-06 10:27:24 -0600142 """Tests the ChecKError() function"""
Simon Glass04afdfe2022-07-30 20:57:10 -0600143 with self.assertRaises(ValueError) as exc:
Simon Glass9c526332018-07-06 10:27:28 -0600144 fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
Simon Glass04afdfe2022-07-30 20:57:10 -0600145 self.assertIn('FDT_ERR_NOTFOUND: hello', str(exc.exception))
Simon Glass0ed50752018-07-06 10:27:24 -0600146
Simon Glass04afdfe2022-07-30 20:57:10 -0600147 def test_get_fdt(self):
148 """Test getting an Fdt object from a node"""
Simon Glasse2d65282018-07-17 13:25:46 -0600149 node = self.dtb.GetNode('/spl-test')
150 self.assertEqual(self.dtb, node.GetFdt())
Simon Glass0ed50752018-07-06 10:27:24 -0600151
Simon Glass04afdfe2022-07-30 20:57:10 -0600152 def test_bytes_to_value(self):
153 """Test converting a string list into Python"""
Simon Glass5872f0c2019-05-17 22:00:41 -0600154 self.assertEqual(BytesToValue(b'this\0is\0'),
Simon Glassc9a032c2020-11-08 20:36:17 -0700155 (Type.STRING, ['this', 'is']))
Simon Glass5872f0c2019-05-17 22:00:41 -0600156
Simon Glass0ed50752018-07-06 10:27:24 -0600157class TestNode(unittest.TestCase):
158 """Test operation of the Node class"""
159
160 @classmethod
161 def setUpClass(cls):
Simon Glass80025522022-01-29 14:14:04 -0700162 tools.prepare_output_dir(None)
Simon Glass0ed50752018-07-06 10:27:24 -0600163
164 @classmethod
165 def tearDownClass(cls):
Simon Glass80025522022-01-29 14:14:04 -0700166 tools.finalise_output_dir()
Simon Glass0ed50752018-07-06 10:27:24 -0600167
168 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700169 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass0ed50752018-07-06 10:27:24 -0600170 self.node = self.dtb.GetNode('/spl-test')
Simon Glass244548f2021-03-21 18:24:37 +1300171 self.fdt = self.dtb.GetFdtObj()
Simon Glass0ed50752018-07-06 10:27:24 -0600172
Simon Glass04afdfe2022-07-30 20:57:10 -0600173 def test_offset(self):
Simon Glass0ed50752018-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 Glass04afdfe2022-07-30 20:57:10 -0600177 def test_delete(self):
Simon Glass0ed50752018-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 Glass9c526332018-07-06 10:27:28 -0600187 with self.assertRaises(libfdt.FdtException):
188 self.node.DeleteProp('missing')
Simon Glass0ed50752018-07-06 10:27:24 -0600189
Simon Glass04afdfe2022-07-30 20:57:10 -0600190 def test_delete_get_offset(self):
Simon Glass4df8a0c2018-07-06 10:27:29 -0600191 """Test that property offset update when properties are deleted"""
192 self.node.DeleteProp('intval')
Simon Glass04afdfe2022-07-30 20:57:10 -0600193 prop, value = _get_property_value(self.dtb, self.node, 'longbytearray')
Simon Glass4df8a0c2018-07-06 10:27:29 -0600194 self.assertEqual(prop.value, value)
195
Simon Glass04afdfe2022-07-30 20:57:10 -0600196 def test_find_node(self):
Simon Glassaa1a5d72018-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 Glass0ed50752018-07-06 10:27:24 -0600199 self.assertEqual('i2c@0', node.name)
Simon Glassaa1a5d72018-07-17 13:25:41 -0600200 subnode = node.FindNode('pmic@9')
Simon Glass0ed50752018-07-06 10:27:24 -0600201 self.assertEqual('pmic@9', subnode.name)
Simon Glassaa1a5d72018-07-17 13:25:41 -0600202 self.assertEqual(None, node.FindNode('missing'))
Simon Glass0ed50752018-07-06 10:27:24 -0600203
Simon Glass04afdfe2022-07-30 20:57:10 -0600204 def test_refresh_missing_node(self):
Simon Glass4df8a0c2018-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 Glass04afdfe2022-07-30 20:57:10 -0600208 with self.assertRaises(ValueError) as exc:
Simon Glass4df8a0c2018-07-06 10:27:29 -0600209 self.dtb.Refresh()
Simon Glass04afdfe2022-07-30 20:57:10 -0600210 self.assertIn('Internal error, offset', str(exc.exception))
Simon Glass4df8a0c2018-07-06 10:27:29 -0600211
Simon Glass04afdfe2022-07-30 20:57:10 -0600212 def test_refresh_extra_node(self):
Simon Glass4df8a0c2018-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 Glass244548f2021-03-21 18:24:37 +1300215 self.fdt.del_node(self.node.Offset())
Simon Glass04afdfe2022-07-30 20:57:10 -0600216 with self.assertRaises(ValueError) as exc:
Simon Glass4df8a0c2018-07-06 10:27:29 -0600217 self.dtb.Refresh()
218 self.assertIn('Internal error, node name mismatch '
Simon Glass04afdfe2022-07-30 20:57:10 -0600219 'spl-test != spl-test2', str(exc.exception))
Simon Glass4df8a0c2018-07-06 10:27:29 -0600220
Simon Glass04afdfe2022-07-30 20:57:10 -0600221 def test_refresh_missing_prop(self):
Simon Glass4df8a0c2018-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 Glass04afdfe2022-07-30 20:57:10 -0600225 with self.assertRaises(ValueError) as exc:
Simon Glass4df8a0c2018-07-06 10:27:29 -0600226 self.dtb.Refresh()
Simon Glass93f18a12021-03-21 18:24:34 +1300227 self.assertIn("Internal error, node '/spl-test' property 'notstring' missing, offset ",
Simon Glass04afdfe2022-07-30 20:57:10 -0600228 str(exc.exception))
Simon Glass4df8a0c2018-07-06 10:27:29 -0600229
Simon Glass04afdfe2022-07-30 20:57:10 -0600230 def test_lookup_phandle(self):
Simon Glasse2d65282018-07-17 13:25:46 -0600231 """Test looking up a single phandle"""
Simon Glass4f4b2402021-02-03 06:00:56 -0700232 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glasse2d65282018-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 Glass04afdfe2022-07-30 20:57:10 -0600238 def test_add_node_space(self):
Simon Glass244548f2021-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 Glass04afdfe2022-07-30 20:57:10 -0600242 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glass244548f2021-03-21 18:24:37 +1300243 self.dtb.Sync(auto_resize=False)
Simon Glass04afdfe2022-07-30 20:57:10 -0600244 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glass244548f2021-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 Glass04afdfe2022-07-30 20:57:10 -0600250 def test_add_nodes(self):
Simon Glass244548f2021-03-21 18:24:37 +1300251 """Test adding various subnode and properies"""
252 node = self.dtb.GetNode('/i2c@0')
253
Simon Glass3be798a2021-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 Glass244548f2021-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 Glass04afdfe2022-07-30 20:57:10 -0600282 def test_add_one_node(self):
Simon Glass00238612022-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 Glass04afdfe2022-07-30 20:57:10 -0600293 def test_refresh_name_mismatch(self):
Simon Glassd8bee462021-03-21 18:24:39 +1300294 """Test name mismatch when syncing nodes and properties"""
Simon Glass04afdfe2022-07-30 20:57:10 -0600295 self.node.AddInt('integer-a', 12)
Simon Glassd8bee462021-03-21 18:24:39 +1300296
297 wrong_offset = self.dtb.GetNode('/i2c@0')._offset
298 self.node._offset = wrong_offset
Simon Glass04afdfe2022-07-30 20:57:10 -0600299 with self.assertRaises(ValueError) as exc:
Simon Glassd8bee462021-03-21 18:24:39 +1300300 self.dtb.Sync()
301 self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
Simon Glass04afdfe2022-07-30 20:57:10 -0600302 str(exc.exception))
Simon Glassd8bee462021-03-21 18:24:39 +1300303
Simon Glass04afdfe2022-07-30 20:57:10 -0600304 with self.assertRaises(ValueError) as exc:
Simon Glassd8bee462021-03-21 18:24:39 +1300305 self.node.Refresh(wrong_offset)
306 self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
Simon Glass04afdfe2022-07-30 20:57:10 -0600307 str(exc.exception))
Simon Glassd8bee462021-03-21 18:24:39 +1300308
Simon Glassadf8e052023-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 Glasscd971192023-07-18 07:24:03 -0600383 def test_copy_subnodes_from_phandles(self):
384 """Test copy_node() function"""
385 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_copy.dts'))
386
387 orig = dtb.GetNode('/')
388 node_list = fdt_util.GetPhandleList(orig, 'copy-list')
389
390 dst = dtb.GetNode('/dest')
391 dst.copy_subnodes_from_phandles(node_list)
392
393 pmic = dtb.GetNode('/dest/over')
394 self.assertTrue(pmic)
395
396 subn = dtb.GetNode('/dest/first@0')
397 self.assertTrue(subn)
398 self.assertEqual({'a-prop', 'b-prop', 'reg'}, subn.props.keys())
399
400 self.assertEqual(
401 ['/dest/earlier', '/dest/later', '/dest/over', '/dest/first@0',
402 '/dest/second', '/dest/existing', '/dest/base'],
403 [n.path for n in dst.subnodes])
404
405 # Make sure that the phandle for 'over' is not copied
406 over = dst.FindNode('over')
407 print('keys', over.props.keys())
408 self.assertNotIn('phandle', over.props.keys())
409
410 # Check the merged properties, first the base ones in '/dest'
411 expect = {'bootph-all', 'compatible', 'stringarray', 'longbytearray',
412 'maybe-empty-int'}
413
414 # Properties from 'base'
415 expect.update({'#address-cells', '#size-cells'})
416
417 # Properties from 'another'
418 expect.add('new-prop')
419
420 self.assertEqual(expect, set(dst.props.keys()))
421
Simon Glass0ed50752018-07-06 10:27:24 -0600422
423class TestProp(unittest.TestCase):
424 """Test operation of the Prop class"""
425
426 @classmethod
427 def setUpClass(cls):
Simon Glass80025522022-01-29 14:14:04 -0700428 tools.prepare_output_dir(None)
Simon Glass0ed50752018-07-06 10:27:24 -0600429
430 @classmethod
431 def tearDownClass(cls):
Simon Glass80025522022-01-29 14:14:04 -0700432 tools.finalise_output_dir()
Simon Glass0ed50752018-07-06 10:27:24 -0600433
434 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700435 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass0ed50752018-07-06 10:27:24 -0600436 self.node = self.dtb.GetNode('/spl-test')
437 self.fdt = self.dtb.GetFdtObj()
438
Simon Glass04afdfe2022-07-30 20:57:10 -0600439 def test_missing_node(self):
440 """Test GetNode() when the node is missing"""
Simon Glassc5eddc82018-07-06 10:27:30 -0600441 self.assertEqual(None, self.dtb.GetNode('missing'))
442
Simon Glass04afdfe2022-07-30 20:57:10 -0600443 def test_phandle(self):
444 """Test GetNode() on a phandle"""
Simon Glass4f4b2402021-02-03 06:00:56 -0700445 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass609e2b12018-07-06 10:27:31 -0600446 node = dtb.GetNode('/phandle-source2')
447 prop = node.props['clocks']
448 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass9c526332018-07-06 10:27:28 -0600449
Simon Glass04afdfe2022-07-30 20:57:10 -0600450 def _convert_prop(self, prop_name):
Simon Glass9c526332018-07-06 10:27:28 -0600451 """Helper function to look up a property in self.node and return it
452
453 Args:
Simon Glass04afdfe2022-07-30 20:57:10 -0600454 str: Property name to find
Simon Glass9c526332018-07-06 10:27:28 -0600455
Simon Glass04afdfe2022-07-30 20:57:10 -0600456 Returns:
457 fdt.Prop: object for this property
Simon Glass9c526332018-07-06 10:27:28 -0600458 """
Simon Glass04afdfe2022-07-30 20:57:10 -0600459 prop = self.fdt.getprop(self.node.Offset(), prop_name)
460 return fdt.Prop(self.node, -1, prop_name, prop)
Simon Glass9c526332018-07-06 10:27:28 -0600461
Simon Glass04afdfe2022-07-30 20:57:10 -0600462 def test_make_prop(self):
Simon Glass9c526332018-07-06 10:27:28 -0600463 """Test we can convert all the the types that are supported"""
Simon Glass04afdfe2022-07-30 20:57:10 -0600464 prop = self._convert_prop('boolval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700465 self.assertEqual(Type.BOOL, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600466 self.assertEqual(True, prop.value)
467
Simon Glass04afdfe2022-07-30 20:57:10 -0600468 prop = self._convert_prop('intval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700469 self.assertEqual(Type.INT, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600470 self.assertEqual(1, fdt32_to_cpu(prop.value))
471
Simon Glass04afdfe2022-07-30 20:57:10 -0600472 prop = self._convert_prop('int64val')
Simon Glass3b55e3f2021-11-23 11:03:39 -0700473 self.assertEqual(Type.INT, prop.type)
474 self.assertEqual(0x123456789abcdef0, fdt64_to_cpu(prop.value))
475
Simon Glass04afdfe2022-07-30 20:57:10 -0600476 prop = self._convert_prop('intarray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700477 self.assertEqual(Type.INT, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600478 val = [fdt32_to_cpu(val) for val in prop.value]
479 self.assertEqual([2, 3, 4], val)
480
Simon Glass04afdfe2022-07-30 20:57:10 -0600481 prop = self._convert_prop('byteval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700482 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600483 self.assertEqual(5, ord(prop.value))
484
Simon Glass04afdfe2022-07-30 20:57:10 -0600485 prop = self._convert_prop('longbytearray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700486 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600487 val = [ord(val) for val in prop.value]
488 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
489
Simon Glass04afdfe2022-07-30 20:57:10 -0600490 prop = self._convert_prop('stringval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700491 self.assertEqual(Type.STRING, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600492 self.assertEqual('message', prop.value)
493
Simon Glass04afdfe2022-07-30 20:57:10 -0600494 prop = self._convert_prop('stringarray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700495 self.assertEqual(Type.STRING, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600496 self.assertEqual(['multi-word', 'message'], prop.value)
497
Simon Glass04afdfe2022-07-30 20:57:10 -0600498 prop = self._convert_prop('notstring')
Simon Glassc9a032c2020-11-08 20:36:17 -0700499 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600500 val = [ord(val) for val in prop.value]
501 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
502
Simon Glass04afdfe2022-07-30 20:57:10 -0600503 def test_get_empty(self):
Simon Glass0ed50752018-07-06 10:27:24 -0600504 """Tests the GetEmpty() function for the various supported types"""
Simon Glassc9a032c2020-11-08 20:36:17 -0700505 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
506 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
Simon Glass80025522022-01-29 14:14:04 -0700507 self.assertEqual(tools.get_bytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
Simon Glassc9a032c2020-11-08 20:36:17 -0700508 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass0ed50752018-07-06 10:27:24 -0600509
Simon Glass04afdfe2022-07-30 20:57:10 -0600510 def test_get_offset(self):
Simon Glass0ed50752018-07-06 10:27:24 -0600511 """Test we can get the offset of a property"""
Simon Glass04afdfe2022-07-30 20:57:10 -0600512 prop, value = _get_property_value(self.dtb, self.node, 'longbytearray')
Simon Glass4df8a0c2018-07-06 10:27:29 -0600513 self.assertEqual(prop.value, value)
Simon Glass0ed50752018-07-06 10:27:24 -0600514
Simon Glass04afdfe2022-07-30 20:57:10 -0600515 def test_widen(self):
Simon Glass0ed50752018-07-06 10:27:24 -0600516 """Test widening of values"""
517 node2 = self.dtb.GetNode('/spl-test2')
Simon Glass8034e4d2020-10-03 11:31:27 -0600518 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass0ed50752018-07-06 10:27:24 -0600519 prop = self.node.props['intval']
520
521 # No action
522 prop2 = node2.props['intval']
523 prop.Widen(prop2)
Simon Glassc9a032c2020-11-08 20:36:17 -0700524 self.assertEqual(Type.INT, prop.type)
Simon Glass0ed50752018-07-06 10:27:24 -0600525 self.assertEqual(1, fdt32_to_cpu(prop.value))
526
Simon Glassa7d66982021-07-28 19:23:10 -0600527 # Convert single value to array
Simon Glass0ed50752018-07-06 10:27:24 -0600528 prop2 = self.node.props['intarray']
529 prop.Widen(prop2)
Simon Glassc9a032c2020-11-08 20:36:17 -0700530 self.assertEqual(Type.INT, prop.type)
Simon Glass0ed50752018-07-06 10:27:24 -0600531 self.assertTrue(isinstance(prop.value, list))
532
533 # A 4-byte array looks like a single integer. When widened by a longer
534 # byte array, it should turn into an array.
535 prop = self.node.props['longbytearray']
536 prop2 = node2.props['longbytearray']
Simon Glass8034e4d2020-10-03 11:31:27 -0600537 prop3 = node3.props['longbytearray']
Simon Glass0ed50752018-07-06 10:27:24 -0600538 self.assertFalse(isinstance(prop2.value, list))
539 self.assertEqual(4, len(prop2.value))
Simon Glass8034e4d2020-10-03 11:31:27 -0600540 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass0ed50752018-07-06 10:27:24 -0600541 prop2.Widen(prop)
542 self.assertTrue(isinstance(prop2.value, list))
543 self.assertEqual(9, len(prop2.value))
Simon Glass8034e4d2020-10-03 11:31:27 -0600544 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
545 '\0', '\0', '\0', '\0'], prop2.value)
546 prop3.Widen(prop)
547 self.assertTrue(isinstance(prop3.value, list))
548 self.assertEqual(9, len(prop3.value))
549 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
550 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass0ed50752018-07-06 10:27:24 -0600551
Simon Glass04afdfe2022-07-30 20:57:10 -0600552 def test_widen_more(self):
553 """More tests of widening values"""
554 node2 = self.dtb.GetNode('/spl-test2')
555 node3 = self.dtb.GetNode('/spl-test3')
556 prop = self.node.props['intval']
557
558 # Test widening a single string into a string array
Simon Glass0ed50752018-07-06 10:27:24 -0600559 prop = self.node.props['stringval']
560 prop2 = node2.props['stringarray']
561 self.assertFalse(isinstance(prop.value, list))
562 self.assertEqual(7, len(prop.value))
563 prop.Widen(prop2)
564 self.assertTrue(isinstance(prop.value, list))
565 self.assertEqual(3, len(prop.value))
566
567 # Enlarging an existing array
568 prop = self.node.props['stringarray']
569 prop2 = node2.props['stringarray']
570 self.assertTrue(isinstance(prop.value, list))
571 self.assertEqual(2, len(prop.value))
572 prop.Widen(prop2)
573 self.assertTrue(isinstance(prop.value, list))
574 self.assertEqual(3, len(prop.value))
575
Simon Glassa7d66982021-07-28 19:23:10 -0600576 # Widen an array of ints with an int (should do nothing)
577 prop = self.node.props['intarray']
Simon Glassf42f26e2021-08-02 07:37:54 -0600578 prop2 = node2.props['intval']
Simon Glassa7d66982021-07-28 19:23:10 -0600579 self.assertEqual(Type.INT, prop.type)
580 self.assertEqual(3, len(prop.value))
581 prop.Widen(prop2)
582 self.assertEqual(Type.INT, prop.type)
583 self.assertEqual(3, len(prop.value))
584
Simon Glass43118322021-07-28 19:23:11 -0600585 # Widen an empty bool to an int
586 prop = self.node.props['maybe-empty-int']
587 prop3 = node3.props['maybe-empty-int']
588 self.assertEqual(Type.BOOL, prop.type)
589 self.assertEqual(True, prop.value)
590 self.assertEqual(Type.INT, prop3.type)
591 self.assertFalse(isinstance(prop.value, list))
592 self.assertEqual(4, len(prop3.value))
593 prop.Widen(prop3)
594 self.assertEqual(Type.INT, prop.type)
595 self.assertTrue(isinstance(prop.value, list))
596 self.assertEqual(1, len(prop.value))
597
Simon Glass04afdfe2022-07-30 20:57:10 -0600598 def test_add(self):
Simon Glasse80c5562018-07-06 10:27:38 -0600599 """Test adding properties"""
600 self.fdt.pack()
601 # This function should automatically expand the device tree
602 self.node.AddZeroProp('one')
603 self.node.AddZeroProp('two')
604 self.node.AddZeroProp('three')
Simon Glasseddd7292018-09-14 04:57:13 -0600605 self.dtb.Sync(auto_resize=True)
Simon Glasse80c5562018-07-06 10:27:38 -0600606
607 # Updating existing properties should be OK, since the device-tree size
608 # does not change
609 self.fdt.pack()
610 self.node.SetInt('one', 1)
611 self.node.SetInt('two', 2)
612 self.node.SetInt('three', 3)
Simon Glasseddd7292018-09-14 04:57:13 -0600613 self.dtb.Sync(auto_resize=False)
Simon Glasse80c5562018-07-06 10:27:38 -0600614
615 # This should fail since it would need to increase the device-tree size
Simon Glasseddd7292018-09-14 04:57:13 -0600616 self.node.AddZeroProp('four')
Simon Glass04afdfe2022-07-30 20:57:10 -0600617 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glasseddd7292018-09-14 04:57:13 -0600618 self.dtb.Sync(auto_resize=False)
Simon Glass04afdfe2022-07-30 20:57:10 -0600619 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glassccd25262018-09-14 04:57:16 -0600620 self.dtb.Sync(auto_resize=True)
Simon Glasse80c5562018-07-06 10:27:38 -0600621
Simon Glass04afdfe2022-07-30 20:57:10 -0600622 def test_add_more(self):
Simon Glassccd25262018-09-14 04:57:16 -0600623 """Test various other methods for adding and setting properties"""
624 self.node.AddZeroProp('one')
625 self.dtb.Sync(auto_resize=True)
626 data = self.fdt.getprop(self.node.Offset(), 'one')
627 self.assertEqual(0, fdt32_to_cpu(data))
628
629 self.node.SetInt('one', 1)
630 self.dtb.Sync(auto_resize=False)
631 data = self.fdt.getprop(self.node.Offset(), 'one')
632 self.assertEqual(1, fdt32_to_cpu(data))
633
Simon Glassa2af7302021-01-06 21:35:18 -0700634 val = 1234
635 self.node.AddInt('integer', val)
636 self.dtb.Sync(auto_resize=True)
637 data = self.fdt.getprop(self.node.Offset(), 'integer')
638 self.assertEqual(val, fdt32_to_cpu(data))
639
Simon Glassccd25262018-09-14 04:57:16 -0600640 val = '123' + chr(0) + '456'
641 self.node.AddString('string', val)
642 self.dtb.Sync(auto_resize=True)
643 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glass80025522022-01-29 14:14:04 -0700644 self.assertEqual(tools.to_bytes(val) + b'\0', data)
Simon Glassccd25262018-09-14 04:57:16 -0600645
646 self.fdt.pack()
647 self.node.SetString('string', val + 'x')
Simon Glass04afdfe2022-07-30 20:57:10 -0600648 with self.assertRaises(libfdt.FdtException) as exc:
Simon Glassccd25262018-09-14 04:57:16 -0600649 self.dtb.Sync(auto_resize=False)
Simon Glass04afdfe2022-07-30 20:57:10 -0600650 self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
Simon Glassccd25262018-09-14 04:57:16 -0600651 self.node.SetString('string', val[:-1])
652
653 prop = self.node.props['string']
Simon Glass80025522022-01-29 14:14:04 -0700654 prop.SetData(tools.to_bytes(val))
Simon Glassccd25262018-09-14 04:57:16 -0600655 self.dtb.Sync(auto_resize=False)
656 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glass80025522022-01-29 14:14:04 -0700657 self.assertEqual(tools.to_bytes(val), data)
Simon Glassccd25262018-09-14 04:57:16 -0600658
659 self.node.AddEmptyProp('empty', 5)
660 self.dtb.Sync(auto_resize=True)
661 prop = self.node.props['empty']
Simon Glass80025522022-01-29 14:14:04 -0700662 prop.SetData(tools.to_bytes(val))
Simon Glassccd25262018-09-14 04:57:16 -0600663 self.dtb.Sync(auto_resize=False)
664 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glass80025522022-01-29 14:14:04 -0700665 self.assertEqual(tools.to_bytes(val), data)
Simon Glassccd25262018-09-14 04:57:16 -0600666
Simon Glass1cd40082019-05-17 22:00:36 -0600667 self.node.SetData('empty', b'123')
668 self.assertEqual(b'123', prop.bytes)
Simon Glassccd25262018-09-14 04:57:16 -0600669
Simon Glassf67c99c2020-07-09 18:39:44 -0600670 # Trying adding a lot of data at once
Simon Glass80025522022-01-29 14:14:04 -0700671 self.node.AddData('data', tools.get_bytes(65, 20000))
Simon Glassf67c99c2020-07-09 18:39:44 -0600672 self.dtb.Sync(auto_resize=True)
673
Simon Glass452be422022-02-08 11:49:50 -0700674 def test_string_list(self):
675 """Test adding string-list property to a node"""
676 val = ['123', '456']
677 self.node.AddStringList('stringlist', val)
678 self.dtb.Sync(auto_resize=True)
679 data = self.fdt.getprop(self.node.Offset(), 'stringlist')
680 self.assertEqual(b'123\x00456\0', data)
681
Simon Glass120fa002022-03-05 20:18:56 -0700682 val = []
683 self.node.AddStringList('stringlist', val)
684 self.dtb.Sync(auto_resize=True)
685 data = self.fdt.getprop(self.node.Offset(), 'stringlist')
686 self.assertEqual(b'', data)
687
Simon Glassb9b5cb32022-02-08 11:49:51 -0700688 def test_delete_node(self):
689 """Test deleting a node"""
690 old_offset = self.fdt.path_offset('/spl-test')
691 self.assertGreater(old_offset, 0)
692 self.node.Delete()
693 self.dtb.Sync()
694 new_offset = self.fdt.path_offset('/spl-test', libfdt.QUIET_NOTFOUND)
695 self.assertEqual(-libfdt.NOTFOUND, new_offset)
696
Simon Glass04afdfe2022-07-30 20:57:10 -0600697 def test_from_data(self):
698 """Test creating an FDT from data"""
Simon Glassb8a49292018-09-14 04:57:17 -0600699 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
700 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
701
702 self.node.AddEmptyProp('empty', 5)
703 self.dtb.Sync(auto_resize=True)
704 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
705
Simon Glass04afdfe2022-07-30 20:57:10 -0600706 def test_missing_set_int(self):
Simon Glassa683a5f2019-07-20 12:23:37 -0600707 """Test handling of a missing property with SetInt"""
Simon Glass04afdfe2022-07-30 20:57:10 -0600708 with self.assertRaises(ValueError) as exc:
Simon Glassa683a5f2019-07-20 12:23:37 -0600709 self.node.SetInt('one', 1)
710 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass04afdfe2022-07-30 20:57:10 -0600711 str(exc.exception))
Simon Glassa683a5f2019-07-20 12:23:37 -0600712
Simon Glass04afdfe2022-07-30 20:57:10 -0600713 def test_missing_set_data(self):
Simon Glassa683a5f2019-07-20 12:23:37 -0600714 """Test handling of a missing property with SetData"""
Simon Glass04afdfe2022-07-30 20:57:10 -0600715 with self.assertRaises(ValueError) as exc:
Simon Glassa683a5f2019-07-20 12:23:37 -0600716 self.node.SetData('one', b'data')
717 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass04afdfe2022-07-30 20:57:10 -0600718 str(exc.exception))
Simon Glassa683a5f2019-07-20 12:23:37 -0600719
Simon Glass04afdfe2022-07-30 20:57:10 -0600720 def test_missing_set_string(self):
Simon Glassa683a5f2019-07-20 12:23:37 -0600721 """Test handling of a missing property with SetString"""
Simon Glass04afdfe2022-07-30 20:57:10 -0600722 with self.assertRaises(ValueError) as exc:
Simon Glassa683a5f2019-07-20 12:23:37 -0600723 self.node.SetString('one', 1)
724 self.assertIn("node '/spl-test': Missing property 'one'",
Simon Glass04afdfe2022-07-30 20:57:10 -0600725 str(exc.exception))
Simon Glassa683a5f2019-07-20 12:23:37 -0600726
Simon Glass04afdfe2022-07-30 20:57:10 -0600727 def test_get_filename(self):
Simon Glass74f5feb2019-07-20 12:24:08 -0600728 """Test the dtb filename can be provided"""
Simon Glass80025522022-01-29 14:14:04 -0700729 self.assertEqual(tools.get_output_filename('source.dtb'),
Simon Glass74f5feb2019-07-20 12:24:08 -0600730 self.dtb.GetFilename())
731
Simon Glass0ed50752018-07-06 10:27:24 -0600732
Simon Glass9c526332018-07-06 10:27:28 -0600733class TestFdtUtil(unittest.TestCase):
734 """Tests for the fdt_util module
735
736 This module will likely be mostly replaced at some point, once upstream
737 libfdt has better Python support. For now, this provides tests for current
738 functionality.
739 """
740 @classmethod
741 def setUpClass(cls):
Simon Glass80025522022-01-29 14:14:04 -0700742 tools.prepare_output_dir(None)
Simon Glass9c526332018-07-06 10:27:28 -0600743
Simon Glass752e7552018-10-01 21:12:41 -0600744 @classmethod
745 def tearDownClass(cls):
Simon Glass80025522022-01-29 14:14:04 -0700746 tools.finalise_output_dir()
Simon Glass752e7552018-10-01 21:12:41 -0600747
Simon Glass9c526332018-07-06 10:27:28 -0600748 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700749 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass9c526332018-07-06 10:27:28 -0600750 self.node = self.dtb.GetNode('/spl-test')
751
Simon Glass04afdfe2022-07-30 20:57:10 -0600752 def test_get_int(self):
753 """Test getting an int from a node"""
Simon Glass9c526332018-07-06 10:27:28 -0600754 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
755 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
756
Simon Glass04afdfe2022-07-30 20:57:10 -0600757 with self.assertRaises(ValueError) as exc:
Simon Glass3b55e3f2021-11-23 11:03:39 -0700758 fdt_util.GetInt(self.node, 'intarray')
Simon Glass9c526332018-07-06 10:27:28 -0600759 self.assertIn("property 'intarray' has list value: expecting a single "
Simon Glass04afdfe2022-07-30 20:57:10 -0600760 'integer', str(exc.exception))
Simon Glass9c526332018-07-06 10:27:28 -0600761
Simon Glass04afdfe2022-07-30 20:57:10 -0600762 def test_get_int64(self):
763 """Test getting a 64-bit int from a node"""
Simon Glass3b55e3f2021-11-23 11:03:39 -0700764 self.assertEqual(0x123456789abcdef0,
765 fdt_util.GetInt64(self.node, 'int64val'))
766 self.assertEqual(3, fdt_util.GetInt64(self.node, 'missing', 3))
767
Simon Glass04afdfe2022-07-30 20:57:10 -0600768 with self.assertRaises(ValueError) as exc:
Simon Glass3b55e3f2021-11-23 11:03:39 -0700769 fdt_util.GetInt64(self.node, 'intarray')
770 self.assertIn(
771 "property 'intarray' should be a list with 2 items for 64-bit values",
Simon Glass04afdfe2022-07-30 20:57:10 -0600772 str(exc.exception))
Simon Glass3b55e3f2021-11-23 11:03:39 -0700773
Simon Glass04afdfe2022-07-30 20:57:10 -0600774 def test_get_string(self):
775 """Test getting a string from a node"""
Simon Glass9c526332018-07-06 10:27:28 -0600776 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
777 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
778 'test'))
Simon Glass120fa002022-03-05 20:18:56 -0700779 self.assertEqual('', fdt_util.GetString(self.node, 'boolval'))
Simon Glass9c526332018-07-06 10:27:28 -0600780
Simon Glass04afdfe2022-07-30 20:57:10 -0600781 with self.assertRaises(ValueError) as exc:
Simon Glass9c526332018-07-06 10:27:28 -0600782 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
783 self.assertIn("property 'stringarray' has list value: expecting a "
Simon Glass04afdfe2022-07-30 20:57:10 -0600784 'single string', str(exc.exception))
Simon Glass9c526332018-07-06 10:27:28 -0600785
Simon Glass04afdfe2022-07-30 20:57:10 -0600786 def test_get_string_list(self):
787 """Test getting a string list from a node"""
Simon Glassb2e88612021-11-23 21:09:51 -0700788 self.assertEqual(['message'],
789 fdt_util.GetStringList(self.node, 'stringval'))
790 self.assertEqual(
791 ['multi-word', 'message'],
792 fdt_util.GetStringList(self.node, 'stringarray'))
793 self.assertEqual(['test'],
794 fdt_util.GetStringList(self.node, 'missing', ['test']))
Simon Glass120fa002022-03-05 20:18:56 -0700795 self.assertEqual([], fdt_util.GetStringList(self.node, 'boolval'))
Simon Glassb2e88612021-11-23 21:09:51 -0700796
Simon Glass04afdfe2022-07-30 20:57:10 -0600797 def test_get_args(self):
798 """Test getting arguments from a node"""
Simon Glass738a54d2022-02-08 11:49:53 -0700799 node = self.dtb.GetNode('/orig-node')
800 self.assertEqual(['message'], fdt_util.GetArgs(self.node, 'stringval'))
801 self.assertEqual(
802 ['multi-word', 'message'],
803 fdt_util.GetArgs(self.node, 'stringarray'))
804 self.assertEqual([], fdt_util.GetArgs(self.node, 'boolval'))
Simon Glassc6b3cdc2022-03-05 20:18:52 -0700805 self.assertEqual(['-n first', 'second', '-p', '123,456', '-x'],
Simon Glass738a54d2022-02-08 11:49:53 -0700806 fdt_util.GetArgs(node, 'args'))
Simon Glassc6b3cdc2022-03-05 20:18:52 -0700807 self.assertEqual(['a space', 'there'],
808 fdt_util.GetArgs(node, 'args2'))
809 self.assertEqual(['-n', 'first', 'second', '-p', '123,456', '-x'],
810 fdt_util.GetArgs(node, 'args3'))
Simon Glass738a54d2022-02-08 11:49:53 -0700811 with self.assertRaises(ValueError) as exc:
812 fdt_util.GetArgs(self.node, 'missing')
813 self.assertIn(
814 "Node '/spl-test': Expected property 'missing'",
815 str(exc.exception))
816
Simon Glass04afdfe2022-07-30 20:57:10 -0600817 def test_get_bool(self):
818 """Test getting a bool from a node"""
Simon Glass9c526332018-07-06 10:27:28 -0600819 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
820 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
821 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
822 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
823
Simon Glass04afdfe2022-07-30 20:57:10 -0600824 def test_get_byte(self):
825 """Test getting a byte from a node"""
Simon Glass53f53992018-07-17 13:25:40 -0600826 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
827 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
828
Simon Glass04afdfe2022-07-30 20:57:10 -0600829 with self.assertRaises(ValueError) as exc:
Simon Glass53f53992018-07-17 13:25:40 -0600830 fdt_util.GetByte(self.node, 'longbytearray')
831 self.assertIn("property 'longbytearray' has list value: expecting a "
Simon Glass04afdfe2022-07-30 20:57:10 -0600832 'single byte', str(exc.exception))
Simon Glass53f53992018-07-17 13:25:40 -0600833
Simon Glass04afdfe2022-07-30 20:57:10 -0600834 with self.assertRaises(ValueError) as exc:
Simon Glass53f53992018-07-17 13:25:40 -0600835 fdt_util.GetByte(self.node, 'intval')
836 self.assertIn("property 'intval' has length 4, expecting 1",
Simon Glass04afdfe2022-07-30 20:57:10 -0600837 str(exc.exception))
Simon Glass53f53992018-07-17 13:25:40 -0600838
Simon Glass04afdfe2022-07-30 20:57:10 -0600839 def test_get_bytes(self):
840 """Test getting multiple bytes from a node"""
Simon Glass0e055bf2021-11-23 11:03:40 -0700841 self.assertEqual(bytes([5]), fdt_util.GetBytes(self.node, 'byteval', 1))
842 self.assertEqual(None, fdt_util.GetBytes(self.node, 'missing', 3))
843 self.assertEqual(
844 bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3, bytes([3])))
845
Simon Glass04afdfe2022-07-30 20:57:10 -0600846 with self.assertRaises(ValueError) as exc:
Simon Glass0e055bf2021-11-23 11:03:40 -0700847 fdt_util.GetBytes(self.node, 'longbytearray', 7)
848 self.assertIn(
849 "Node 'spl-test' property 'longbytearray' has length 9, expecting 7",
Simon Glass04afdfe2022-07-30 20:57:10 -0600850 str(exc.exception))
Simon Glass0e055bf2021-11-23 11:03:40 -0700851
852 self.assertEqual(
853 bytes([0, 0, 0, 1]), fdt_util.GetBytes(self.node, 'intval', 4))
854 self.assertEqual(
855 bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3, bytes([3])))
856
Simon Glass04afdfe2022-07-30 20:57:10 -0600857 def test_get_phandle_list(self):
858 """Test getting a list of phandles from a node"""
Simon Glass4f4b2402021-02-03 06:00:56 -0700859 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glasse2d65282018-07-17 13:25:46 -0600860 node = dtb.GetNode('/phandle-source2')
861 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
862 node = dtb.GetNode('/phandle-source')
863 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
864 fdt_util.GetPhandleList(node, 'clocks'))
865 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
866
Simon Glass04afdfe2022-07-30 20:57:10 -0600867 def test_get_data_type(self):
868 """Test getting a value of a particular type from a node"""
Simon Glass91710b32018-07-17 13:25:32 -0600869 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
870 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
871 str))
Simon Glass04afdfe2022-07-30 20:57:10 -0600872 with self.assertRaises(ValueError):
Simon Glass91710b32018-07-17 13:25:32 -0600873 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
874 bool))
Simon Glass04afdfe2022-07-30 20:57:10 -0600875 def test_fdt_cells_to_cpu(self):
876 """Test getting cells with the correct endianness"""
Simon Glass9c526332018-07-06 10:27:28 -0600877 val = self.node.props['intarray'].value
878 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
879 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
880
Simon Glass4f4b2402021-02-03 06:00:56 -0700881 dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
Simon Glassb0a34a42019-05-17 22:00:40 -0600882 node1 = dtb2.GetNode('/test1')
883 val = node1.props['reg'].value
Simon Glass9c526332018-07-06 10:27:28 -0600884 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
885
Simon Glassb0a34a42019-05-17 22:00:40 -0600886 node2 = dtb2.GetNode('/test2')
887 val = node2.props['reg'].value
888 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
889 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
890 2))
891 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
892
Simon Glass04afdfe2022-07-30 20:57:10 -0600893 def test_ensure_compiled(self):
Simon Glassb8d2daa2019-07-20 12:23:49 -0600894 """Test a degenerate case of this function (file already compiled)"""
Simon Glass4f4b2402021-02-03 06:00:56 -0700895 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass9c526332018-07-06 10:27:28 -0600896 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
897
Simon Glass04afdfe2022-07-30 20:57:10 -0600898 def test_ensure_compiled_tmpdir(self):
Simon Glassb8d2daa2019-07-20 12:23:49 -0600899 """Test providing a temporary directory"""
Heinrich Schuchardte72dcd42023-04-20 20:03:43 +0200900 old_outdir = tools.outdir
Simon Glassb8d2daa2019-07-20 12:23:49 -0600901 try:
Simon Glassb8d2daa2019-07-20 12:23:49 -0600902 tools.outdir= None
903 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
Simon Glass4f4b2402021-02-03 06:00:56 -0700904 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
Simon Glassb8d2daa2019-07-20 12:23:49 -0600905 tmpdir)
906 self.assertEqual(tmpdir, os.path.dirname(dtb))
907 shutil.rmtree(tmpdir)
908 finally:
Heinrich Schuchardte72dcd42023-04-20 20:03:43 +0200909 tools.outdir = old_outdir
Simon Glassb8d2daa2019-07-20 12:23:49 -0600910
Simon Glasse8cea0e2023-01-11 16:10:18 -0700911 def test_get_phandle_name_offset(self):
912 val = fdt_util.GetPhandleNameOffset(self.node, 'missing')
913 self.assertIsNone(val)
914
915 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
916 node = dtb.GetNode('/phandle-source')
917 node, name, offset = fdt_util.GetPhandleNameOffset(node,
918 'phandle-name-offset')
919 self.assertEqual('phandle3-target', node.name)
920 self.assertEqual('fred', name)
921 self.assertEqual(123, offset)
Simon Glass9c526332018-07-06 10:27:28 -0600922
Simon Glass9852bef2022-07-30 20:57:05 -0600923def run_test_coverage(build_dir):
924 """Run the tests and check that we get 100% coverage
925
926 Args:
927 build_dir (str): Directory containing the build output
928 """
Simon Glass1b53d902022-01-29 14:14:14 -0700929 test_util.run_test_coverage('tools/dtoc/test_fdt.py', None,
Simon Glass131444f2023-02-23 18:18:04 -0700930 ['tools/patman/*.py', 'tools/u_boot_pylib/*', '*test_fdt.py'],
931 build_dir)
Simon Glass9c526332018-07-06 10:27:28 -0600932
933
Simon Glass882f6322022-07-30 20:57:09 -0600934def run_tests(names, processes):
Simon Glass0ed50752018-07-06 10:27:24 -0600935 """Run all the test we have for the fdt model
936
937 Args:
Simon Glass882f6322022-07-30 20:57:09 -0600938 names (list of str): List of test names provided. Only the first is used
Simon Glass8726f662022-07-30 20:57:06 -0600939 processes (int): Number of processes to use (None means as many as there
940 are CPUs on the system. This must be set to 1 when running under
941 the python3-coverage tool
Simon Glass77164ee2022-03-18 18:01:50 -0600942
943 Returns:
Simon Glass8726f662022-07-30 20:57:06 -0600944 int: Return code, 0 on success
Simon Glass0ed50752018-07-06 10:27:24 -0600945 """
Simon Glass882f6322022-07-30 20:57:09 -0600946 test_name = names[0] if names else None
Alper Nebi Yasakca1c5882022-04-02 20:06:06 +0300947 result = test_util.run_test_suites(
Simon Glassb6ec10c2022-07-30 20:57:07 -0600948 'test_fdt', False, False, False, processes, test_name, None,
Simon Glass77164ee2022-03-18 18:01:50 -0600949 [TestFdt, TestNode, TestProp, TestFdtUtil])
Simon Glass0ed50752018-07-06 10:27:24 -0600950
Alper Nebi Yasakca1c5882022-04-02 20:06:06 +0300951 return (0 if result.wasSuccessful() else 1)
952
Simon Glass0ed50752018-07-06 10:27:24 -0600953
Simon Glass9954cda2022-07-30 20:57:08 -0600954def main():
955 """Main program for this tool"""
Simon Glass882f6322022-07-30 20:57:09 -0600956 parser = ArgumentParser()
957 parser.add_argument('-B', '--build-dir', type=str, default='b',
958 help='Directory containing the build output')
959 parser.add_argument('-P', '--processes', type=int,
960 help='set number of processes to use for running tests')
961 parser.add_argument('-t', '--test', action='store_true', dest='test',
962 default=False, help='run tests')
963 parser.add_argument('-T', '--test-coverage', action='store_true',
964 default=False,
965 help='run tests and check for 100% coverage')
966 parser.add_argument('name', nargs='*')
967 args = parser.parse_args()
Simon Glass0ed50752018-07-06 10:27:24 -0600968
Simon Glass9954cda2022-07-30 20:57:08 -0600969 # Run our meagre tests
Simon Glass882f6322022-07-30 20:57:09 -0600970 if args.test:
971 ret_code = run_tests(args.name, args.processes)
Simon Glass9954cda2022-07-30 20:57:08 -0600972 return ret_code
Simon Glass882f6322022-07-30 20:57:09 -0600973 if args.test_coverage:
974 run_test_coverage(args.build_dir)
Simon Glass9954cda2022-07-30 20:57:08 -0600975 return 0
Simon Glass0ed50752018-07-06 10:27:24 -0600976
Simon Glass9954cda2022-07-30 20:57:08 -0600977if __name__ == '__main__':
978 sys.exit(main())