blob: 856392b1bd9ad4a46a43cccfa82e997acedc3854 [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+
3# Copyright (c) 2018 Google, Inc
4# Written by Simon Glass <sjg@chromium.org>
5#
6
7from optparse import OptionParser
8import glob
9import os
Simon Glassa004f292019-07-20 12:23:49 -060010import shutil
Simon Glass2ba98752018-07-06 10:27:24 -060011import sys
Simon Glassa004f292019-07-20 12:23:49 -060012import tempfile
Simon Glass2ba98752018-07-06 10:27:24 -060013import unittest
14
15# Bring in the patman libraries
16our_path = os.path.dirname(os.path.realpath(__file__))
Simon Glassb4fa9492020-04-17 18:09:05 -060017sys.path.insert(1, os.path.join(our_path, '..'))
Simon Glass2ba98752018-07-06 10:27:24 -060018
Simon Glassbf776672020-04-17 18:09:04 -060019from dtoc import fdt
20from dtoc import fdt_util
21from dtoc.fdt_util import fdt32_to_cpu
Simon Glass5ea9dcc2020-11-08 20:36:17 -070022from fdt import Type, BytesToValue
Simon Glass2ba98752018-07-06 10:27:24 -060023import libfdt
Simon Glassbf776672020-04-17 18:09:04 -060024from patman import command
25from patman import test_util
26from patman import tools
Simon Glass2ba98752018-07-06 10:27:24 -060027
Simon Glassf9b88b32018-07-06 10:27:29 -060028def _GetPropertyValue(dtb, node, prop_name):
29 """Low-level function to get the property value based on its offset
30
31 This looks directly in the device tree at the property's offset to find
32 its value. It is useful as a check that the property is in the correct
33 place.
34
35 Args:
36 node: Node to look in
37 prop_name: Property name to find
38
39 Returns:
40 Tuple:
41 Prop object found
42 Value of property as a string (found using property offset)
43 """
44 prop = node.props[prop_name]
45
46 # Add 12, which is sizeof(struct fdt_property), to get to start of data
47 offset = prop.GetOffset() + 12
48 data = dtb.GetContents()[offset:offset + len(prop.value)]
Simon Glass479dd302020-11-08 20:36:20 -070049 return prop, [chr(x) for x in data]
Simon Glassf9b88b32018-07-06 10:27:29 -060050
Simon Glassdff51a52021-02-03 06:00:56 -070051def find_dtb_file(dts_fname):
52 """Locate a test file in the test/ directory
53
54 Args:
55 dts_fname (str): Filename to find, e.g. 'dtoc_test_simple.dts]
56
57 Returns:
58 str: Path to the test filename
59 """
60 return os.path.join('tools/dtoc/test', dts_fname)
61
Simon Glassf9b88b32018-07-06 10:27:29 -060062
Simon Glass2ba98752018-07-06 10:27:24 -060063class TestFdt(unittest.TestCase):
64 """Tests for the Fdt module
65
66 This includes unit tests for some functions and functional tests for the fdt
67 module.
68 """
69 @classmethod
70 def setUpClass(cls):
71 tools.PrepareOutputDir(None)
72
73 @classmethod
74 def tearDownClass(cls):
Simon Glasse0e62752018-10-01 21:12:41 -060075 tools.FinaliseOutputDir()
Simon Glass2ba98752018-07-06 10:27:24 -060076
77 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -070078 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -060079
80 def testFdt(self):
81 """Test that we can open an Fdt"""
82 self.dtb.Scan()
83 root = self.dtb.GetRoot()
84 self.assertTrue(isinstance(root, fdt.Node))
85
86 def testGetNode(self):
87 """Test the GetNode() method"""
88 node = self.dtb.GetNode('/spl-test')
89 self.assertTrue(isinstance(node, fdt.Node))
Simon Glasse44bc832019-07-20 12:23:39 -060090
Simon Glass2ba98752018-07-06 10:27:24 -060091 node = self.dtb.GetNode('/i2c@0/pmic@9')
92 self.assertTrue(isinstance(node, fdt.Node))
93 self.assertEqual('pmic@9', node.name)
Simon Glass2a2d91d2018-07-06 10:27:28 -060094 self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
Simon Glass2ba98752018-07-06 10:27:24 -060095
Simon Glasse44bc832019-07-20 12:23:39 -060096 node = self.dtb.GetNode('/')
97 self.assertTrue(isinstance(node, fdt.Node))
98 self.assertEqual(0, node.Offset())
99
Simon Glass2ba98752018-07-06 10:27:24 -0600100 def testFlush(self):
101 """Check that we can flush the device tree out to its file"""
102 fname = self.dtb._fname
Simon Glass2ab6e132019-05-17 22:00:39 -0600103 with open(fname, 'rb') as fd:
Simon Glass2ba98752018-07-06 10:27:24 -0600104 data = fd.read()
105 os.remove(fname)
106 with self.assertRaises(IOError):
Simon Glass2ab6e132019-05-17 22:00:39 -0600107 open(fname, 'rb')
Simon Glass2ba98752018-07-06 10:27:24 -0600108 self.dtb.Flush()
Simon Glass2ab6e132019-05-17 22:00:39 -0600109 with open(fname, 'rb') as fd:
Simon Glass2ba98752018-07-06 10:27:24 -0600110 data = fd.read()
111
112 def testPack(self):
113 """Test that packing a device tree works"""
114 self.dtb.Pack()
115
116 def testGetFdt(self):
117 """Tetst that we can access the raw device-tree data"""
Simon Glass96066242018-07-06 10:27:27 -0600118 self.assertTrue(isinstance(self.dtb.GetContents(), bytearray))
Simon Glass2ba98752018-07-06 10:27:24 -0600119
120 def testGetProps(self):
121 """Tests obtaining a list of properties"""
122 node = self.dtb.GetNode('/spl-test')
123 props = self.dtb.GetProps(node)
124 self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
Simon Glass2a2d91d2018-07-06 10:27:28 -0600125 'intarray', 'intval', 'longbytearray', 'notstring',
Simon Glass2ba98752018-07-06 10:27:24 -0600126 'stringarray', 'stringval', 'u-boot,dm-pre-reloc'],
127 sorted(props.keys()))
128
129 def testCheckError(self):
130 """Tests the ChecKError() function"""
131 with self.assertRaises(ValueError) as e:
Simon Glass2a2d91d2018-07-06 10:27:28 -0600132 fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
Simon Glass2ba98752018-07-06 10:27:24 -0600133 self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
134
Simon Glass94a7c602018-07-17 13:25:46 -0600135 def testGetFdt(self):
136 node = self.dtb.GetNode('/spl-test')
137 self.assertEqual(self.dtb, node.GetFdt())
Simon Glass2ba98752018-07-06 10:27:24 -0600138
Simon Glassb5f0daf2019-05-17 22:00:41 -0600139 def testBytesToValue(self):
140 self.assertEqual(BytesToValue(b'this\0is\0'),
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700141 (Type.STRING, ['this', 'is']))
Simon Glassb5f0daf2019-05-17 22:00:41 -0600142
Simon Glass2ba98752018-07-06 10:27:24 -0600143class TestNode(unittest.TestCase):
144 """Test operation of the Node class"""
145
146 @classmethod
147 def setUpClass(cls):
148 tools.PrepareOutputDir(None)
149
150 @classmethod
151 def tearDownClass(cls):
Simon Glasse0e62752018-10-01 21:12:41 -0600152 tools.FinaliseOutputDir()
Simon Glass2ba98752018-07-06 10:27:24 -0600153
154 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700155 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -0600156 self.node = self.dtb.GetNode('/spl-test')
Simon Glass76677dd2021-03-21 18:24:37 +1300157 self.fdt = self.dtb.GetFdtObj()
Simon Glass2ba98752018-07-06 10:27:24 -0600158
159 def testOffset(self):
160 """Tests that we can obtain the offset of a node"""
161 self.assertTrue(self.node.Offset() > 0)
162
163 def testDelete(self):
164 """Tests that we can delete a property"""
165 node2 = self.dtb.GetNode('/spl-test2')
166 offset1 = node2.Offset()
167 self.node.DeleteProp('intval')
168 offset2 = node2.Offset()
169 self.assertTrue(offset2 < offset1)
170 self.node.DeleteProp('intarray')
171 offset3 = node2.Offset()
172 self.assertTrue(offset3 < offset2)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600173 with self.assertRaises(libfdt.FdtException):
174 self.node.DeleteProp('missing')
Simon Glass2ba98752018-07-06 10:27:24 -0600175
Simon Glassf9b88b32018-07-06 10:27:29 -0600176 def testDeleteGetOffset(self):
177 """Test that property offset update when properties are deleted"""
178 self.node.DeleteProp('intval')
179 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
180 self.assertEqual(prop.value, value)
181
Simon Glass2ba98752018-07-06 10:27:24 -0600182 def testFindNode(self):
Simon Glass1d858882018-07-17 13:25:41 -0600183 """Tests that we can find a node using the FindNode() functoin"""
184 node = self.dtb.GetRoot().FindNode('i2c@0')
Simon Glass2ba98752018-07-06 10:27:24 -0600185 self.assertEqual('i2c@0', node.name)
Simon Glass1d858882018-07-17 13:25:41 -0600186 subnode = node.FindNode('pmic@9')
Simon Glass2ba98752018-07-06 10:27:24 -0600187 self.assertEqual('pmic@9', subnode.name)
Simon Glass1d858882018-07-17 13:25:41 -0600188 self.assertEqual(None, node.FindNode('missing'))
Simon Glass2ba98752018-07-06 10:27:24 -0600189
Simon Glassf9b88b32018-07-06 10:27:29 -0600190 def testRefreshMissingNode(self):
191 """Test refreshing offsets when an extra node is present in dtb"""
192 # Delete it from our tables, not the device tree
193 del self.dtb._root.subnodes[-1]
194 with self.assertRaises(ValueError) as e:
195 self.dtb.Refresh()
196 self.assertIn('Internal error, offset', str(e.exception))
197
198 def testRefreshExtraNode(self):
199 """Test refreshing offsets when an expected node is missing"""
200 # Delete it from the device tre, not our tables
Simon Glass76677dd2021-03-21 18:24:37 +1300201 self.fdt.del_node(self.node.Offset())
Simon Glassf9b88b32018-07-06 10:27:29 -0600202 with self.assertRaises(ValueError) as e:
203 self.dtb.Refresh()
204 self.assertIn('Internal error, node name mismatch '
205 'spl-test != spl-test2', str(e.exception))
206
207 def testRefreshMissingProp(self):
208 """Test refreshing offsets when an extra property is present in dtb"""
209 # Delete it from our tables, not the device tree
210 del self.node.props['notstring']
211 with self.assertRaises(ValueError) as e:
212 self.dtb.Refresh()
Simon Glassacd98612021-03-21 18:24:34 +1300213 self.assertIn("Internal error, node '/spl-test' property 'notstring' missing, offset ",
Simon Glassf9b88b32018-07-06 10:27:29 -0600214 str(e.exception))
215
Simon Glass94a7c602018-07-17 13:25:46 -0600216 def testLookupPhandle(self):
217 """Test looking up a single phandle"""
Simon Glassdff51a52021-02-03 06:00:56 -0700218 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass94a7c602018-07-17 13:25:46 -0600219 node = dtb.GetNode('/phandle-source2')
220 prop = node.props['clocks']
221 target = dtb.GetNode('/phandle-target')
222 self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
223
Simon Glass76677dd2021-03-21 18:24:37 +1300224 def testAddNodeSpace(self):
225 """Test adding a single node when out of space"""
226 self.fdt.pack()
227 self.node.AddSubnode('subnode')
228 with self.assertRaises(libfdt.FdtException) as e:
229 self.dtb.Sync(auto_resize=False)
230 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
231
232 self.dtb.Sync(auto_resize=True)
233 offset = self.fdt.path_offset('/spl-test/subnode')
234 self.assertTrue(offset > 0)
235
236 def testAddNodes(self):
237 """Test adding various subnode and properies"""
238 node = self.dtb.GetNode('/i2c@0')
239
Simon Glassf6176652021-03-21 18:24:38 +1300240 # Add one more node next to the pmic one
241 sn1 = node.AddSubnode('node-one')
242 sn1.AddInt('integer-a', 12)
243 sn1.AddInt('integer-b', 23)
244
245 # Sync so that everything is clean
246 self.dtb.Sync(auto_resize=True)
247
248 # Add two subnodes next to pmic and node-one
249 sn2 = node.AddSubnode('node-two')
250 sn2.AddInt('integer-2a', 34)
251 sn2.AddInt('integer-2b', 45)
252
253 sn3 = node.AddSubnode('node-three')
254 sn3.AddInt('integer-3', 123)
255
Simon Glass76677dd2021-03-21 18:24:37 +1300256 # Add a property to the node after i2c@0 to check that this is not
257 # disturbed by adding a subnode to i2c@0
258 orig_node = self.dtb.GetNode('/orig-node')
259 orig_node.AddInt('integer-4', 456)
260
261 # Add a property to the pmic node to check that pmic properties are not
262 # disturbed
263 pmic = self.dtb.GetNode('/i2c@0/pmic@9')
264 pmic.AddInt('integer-5', 567)
265
266 self.dtb.Sync(auto_resize=True)
267
Simon Glass5d1bec32021-03-21 18:24:39 +1300268 def testRefreshNameMismatch(self):
269 """Test name mismatch when syncing nodes and properties"""
270 prop = self.node.AddInt('integer-a', 12)
271
272 wrong_offset = self.dtb.GetNode('/i2c@0')._offset
273 self.node._offset = wrong_offset
274 with self.assertRaises(ValueError) as e:
275 self.dtb.Sync()
276 self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
277 str(e.exception))
278
279 with self.assertRaises(ValueError) as e:
280 self.node.Refresh(wrong_offset)
281 self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
282 str(e.exception))
283
Simon Glass2ba98752018-07-06 10:27:24 -0600284
285class TestProp(unittest.TestCase):
286 """Test operation of the Prop class"""
287
288 @classmethod
289 def setUpClass(cls):
290 tools.PrepareOutputDir(None)
291
292 @classmethod
293 def tearDownClass(cls):
Simon Glasse0e62752018-10-01 21:12:41 -0600294 tools.FinaliseOutputDir()
Simon Glass2ba98752018-07-06 10:27:24 -0600295
296 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700297 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -0600298 self.node = self.dtb.GetNode('/spl-test')
299 self.fdt = self.dtb.GetFdtObj()
300
Simon Glassb9066ff2018-07-06 10:27:30 -0600301 def testMissingNode(self):
302 self.assertEqual(None, self.dtb.GetNode('missing'))
303
Simon Glass2a2d91d2018-07-06 10:27:28 -0600304 def testPhandle(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700305 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass760b7172018-07-06 10:27:31 -0600306 node = dtb.GetNode('/phandle-source2')
307 prop = node.props['clocks']
308 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600309
310 def _ConvertProp(self, prop_name):
311 """Helper function to look up a property in self.node and return it
312
313 Args:
314 Property name to find
315
316 Return fdt.Prop object for this property
317 """
Simon Glass50c59522018-07-26 14:02:13 -0600318 p = self.fdt.getprop(self.node.Offset(), prop_name)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600319 return fdt.Prop(self.node, -1, prop_name, p)
320
321 def testMakeProp(self):
322 """Test we can convert all the the types that are supported"""
323 prop = self._ConvertProp('boolval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700324 self.assertEqual(Type.BOOL, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600325 self.assertEqual(True, prop.value)
326
327 prop = self._ConvertProp('intval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700328 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600329 self.assertEqual(1, fdt32_to_cpu(prop.value))
330
331 prop = self._ConvertProp('intarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700332 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600333 val = [fdt32_to_cpu(val) for val in prop.value]
334 self.assertEqual([2, 3, 4], val)
335
336 prop = self._ConvertProp('byteval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700337 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600338 self.assertEqual(5, ord(prop.value))
339
340 prop = self._ConvertProp('longbytearray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700341 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600342 val = [ord(val) for val in prop.value]
343 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
344
345 prop = self._ConvertProp('stringval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700346 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600347 self.assertEqual('message', prop.value)
348
349 prop = self._ConvertProp('stringarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700350 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600351 self.assertEqual(['multi-word', 'message'], prop.value)
352
353 prop = self._ConvertProp('notstring')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700354 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600355 val = [ord(val) for val in prop.value]
356 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
357
Simon Glass2ba98752018-07-06 10:27:24 -0600358 def testGetEmpty(self):
359 """Tests the GetEmpty() function for the various supported types"""
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700360 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
361 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
362 self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
363 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass2ba98752018-07-06 10:27:24 -0600364
365 def testGetOffset(self):
366 """Test we can get the offset of a property"""
Simon Glassf9b88b32018-07-06 10:27:29 -0600367 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
368 self.assertEqual(prop.value, value)
Simon Glass2ba98752018-07-06 10:27:24 -0600369
370 def testWiden(self):
371 """Test widening of values"""
372 node2 = self.dtb.GetNode('/spl-test2')
Simon Glasse144caf2020-10-03 11:31:27 -0600373 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass2ba98752018-07-06 10:27:24 -0600374 prop = self.node.props['intval']
375
376 # No action
377 prop2 = node2.props['intval']
378 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700379 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600380 self.assertEqual(1, fdt32_to_cpu(prop.value))
381
382 # Convert singla value to array
383 prop2 = self.node.props['intarray']
384 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700385 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600386 self.assertTrue(isinstance(prop.value, list))
387
388 # A 4-byte array looks like a single integer. When widened by a longer
389 # byte array, it should turn into an array.
390 prop = self.node.props['longbytearray']
391 prop2 = node2.props['longbytearray']
Simon Glasse144caf2020-10-03 11:31:27 -0600392 prop3 = node3.props['longbytearray']
Simon Glass2ba98752018-07-06 10:27:24 -0600393 self.assertFalse(isinstance(prop2.value, list))
394 self.assertEqual(4, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600395 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600396 prop2.Widen(prop)
397 self.assertTrue(isinstance(prop2.value, list))
398 self.assertEqual(9, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600399 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
400 '\0', '\0', '\0', '\0'], prop2.value)
401 prop3.Widen(prop)
402 self.assertTrue(isinstance(prop3.value, list))
403 self.assertEqual(9, len(prop3.value))
404 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
405 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600406
407 # Similarly for a string array
408 prop = self.node.props['stringval']
409 prop2 = node2.props['stringarray']
410 self.assertFalse(isinstance(prop.value, list))
411 self.assertEqual(7, len(prop.value))
412 prop.Widen(prop2)
413 self.assertTrue(isinstance(prop.value, list))
414 self.assertEqual(3, len(prop.value))
415
416 # Enlarging an existing array
417 prop = self.node.props['stringarray']
418 prop2 = node2.props['stringarray']
419 self.assertTrue(isinstance(prop.value, list))
420 self.assertEqual(2, len(prop.value))
421 prop.Widen(prop2)
422 self.assertTrue(isinstance(prop.value, list))
423 self.assertEqual(3, len(prop.value))
424
Simon Glass116adec2018-07-06 10:27:38 -0600425 def testAdd(self):
426 """Test adding properties"""
427 self.fdt.pack()
428 # This function should automatically expand the device tree
429 self.node.AddZeroProp('one')
430 self.node.AddZeroProp('two')
431 self.node.AddZeroProp('three')
Simon Glassfa80c252018-09-14 04:57:13 -0600432 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600433
434 # Updating existing properties should be OK, since the device-tree size
435 # does not change
436 self.fdt.pack()
437 self.node.SetInt('one', 1)
438 self.node.SetInt('two', 2)
439 self.node.SetInt('three', 3)
Simon Glassfa80c252018-09-14 04:57:13 -0600440 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600441
442 # This should fail since it would need to increase the device-tree size
Simon Glassfa80c252018-09-14 04:57:13 -0600443 self.node.AddZeroProp('four')
Simon Glass116adec2018-07-06 10:27:38 -0600444 with self.assertRaises(libfdt.FdtException) as e:
Simon Glassfa80c252018-09-14 04:57:13 -0600445 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600446 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
Simon Glass64349612018-09-14 04:57:16 -0600447 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600448
Simon Glass64349612018-09-14 04:57:16 -0600449 def testAddMore(self):
450 """Test various other methods for adding and setting properties"""
451 self.node.AddZeroProp('one')
452 self.dtb.Sync(auto_resize=True)
453 data = self.fdt.getprop(self.node.Offset(), 'one')
454 self.assertEqual(0, fdt32_to_cpu(data))
455
456 self.node.SetInt('one', 1)
457 self.dtb.Sync(auto_resize=False)
458 data = self.fdt.getprop(self.node.Offset(), 'one')
459 self.assertEqual(1, fdt32_to_cpu(data))
460
Simon Glass6eb99322021-01-06 21:35:18 -0700461 val = 1234
462 self.node.AddInt('integer', val)
463 self.dtb.Sync(auto_resize=True)
464 data = self.fdt.getprop(self.node.Offset(), 'integer')
465 self.assertEqual(val, fdt32_to_cpu(data))
466
Simon Glass64349612018-09-14 04:57:16 -0600467 val = '123' + chr(0) + '456'
468 self.node.AddString('string', val)
469 self.dtb.Sync(auto_resize=True)
470 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600471 self.assertEqual(tools.ToBytes(val) + b'\0', data)
Simon Glass64349612018-09-14 04:57:16 -0600472
473 self.fdt.pack()
474 self.node.SetString('string', val + 'x')
475 with self.assertRaises(libfdt.FdtException) as e:
476 self.dtb.Sync(auto_resize=False)
477 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
478 self.node.SetString('string', val[:-1])
479
480 prop = self.node.props['string']
Simon Glassf6b64812019-05-17 22:00:36 -0600481 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600482 self.dtb.Sync(auto_resize=False)
483 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600484 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600485
486 self.node.AddEmptyProp('empty', 5)
487 self.dtb.Sync(auto_resize=True)
488 prop = self.node.props['empty']
Simon Glassf6b64812019-05-17 22:00:36 -0600489 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600490 self.dtb.Sync(auto_resize=False)
491 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glassf6b64812019-05-17 22:00:36 -0600492 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600493
Simon Glassf6b64812019-05-17 22:00:36 -0600494 self.node.SetData('empty', b'123')
495 self.assertEqual(b'123', prop.bytes)
Simon Glass64349612018-09-14 04:57:16 -0600496
Simon Glassc0639172020-07-09 18:39:44 -0600497 # Trying adding a lot of data at once
498 self.node.AddData('data', tools.GetBytes(65, 20000))
499 self.dtb.Sync(auto_resize=True)
500
Simon Glass746aee32018-09-14 04:57:17 -0600501 def testFromData(self):
502 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
503 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
504
505 self.node.AddEmptyProp('empty', 5)
506 self.dtb.Sync(auto_resize=True)
507 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
508
Simon Glassd9dad102019-07-20 12:23:37 -0600509 def testMissingSetInt(self):
510 """Test handling of a missing property with SetInt"""
511 with self.assertRaises(ValueError) as e:
512 self.node.SetInt('one', 1)
513 self.assertIn("node '/spl-test': Missing property 'one'",
514 str(e.exception))
515
516 def testMissingSetData(self):
517 """Test handling of a missing property with SetData"""
518 with self.assertRaises(ValueError) as e:
519 self.node.SetData('one', b'data')
520 self.assertIn("node '/spl-test': Missing property 'one'",
521 str(e.exception))
522
523 def testMissingSetString(self):
524 """Test handling of a missing property with SetString"""
525 with self.assertRaises(ValueError) as e:
526 self.node.SetString('one', 1)
527 self.assertIn("node '/spl-test': Missing property 'one'",
528 str(e.exception))
529
Simon Glassf6e02492019-07-20 12:24:08 -0600530 def testGetFilename(self):
531 """Test the dtb filename can be provided"""
532 self.assertEqual(tools.GetOutputFilename('source.dtb'),
533 self.dtb.GetFilename())
534
Simon Glass2ba98752018-07-06 10:27:24 -0600535
Simon Glass2a2d91d2018-07-06 10:27:28 -0600536class TestFdtUtil(unittest.TestCase):
537 """Tests for the fdt_util module
538
539 This module will likely be mostly replaced at some point, once upstream
540 libfdt has better Python support. For now, this provides tests for current
541 functionality.
542 """
543 @classmethod
544 def setUpClass(cls):
545 tools.PrepareOutputDir(None)
546
Simon Glasse0e62752018-10-01 21:12:41 -0600547 @classmethod
548 def tearDownClass(cls):
549 tools.FinaliseOutputDir()
550
Simon Glass2a2d91d2018-07-06 10:27:28 -0600551 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700552 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600553 self.node = self.dtb.GetNode('/spl-test')
554
555 def testGetInt(self):
556 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
557 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
558
559 with self.assertRaises(ValueError) as e:
560 self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
561 self.assertIn("property 'intarray' has list value: expecting a single "
562 'integer', str(e.exception))
563
564 def testGetString(self):
565 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
566 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
567 'test'))
568
569 with self.assertRaises(ValueError) as e:
570 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
571 self.assertIn("property 'stringarray' has list value: expecting a "
572 'single string', str(e.exception))
573
574 def testGetBool(self):
575 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
576 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
577 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
578 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
579
Simon Glass3af8e492018-07-17 13:25:40 -0600580 def testGetByte(self):
581 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
582 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
583
584 with self.assertRaises(ValueError) as e:
585 fdt_util.GetByte(self.node, 'longbytearray')
586 self.assertIn("property 'longbytearray' has list value: expecting a "
587 'single byte', str(e.exception))
588
589 with self.assertRaises(ValueError) as e:
590 fdt_util.GetByte(self.node, 'intval')
591 self.assertIn("property 'intval' has length 4, expecting 1",
592 str(e.exception))
593
Simon Glass94a7c602018-07-17 13:25:46 -0600594 def testGetPhandleList(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700595 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass94a7c602018-07-17 13:25:46 -0600596 node = dtb.GetNode('/phandle-source2')
597 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
598 node = dtb.GetNode('/phandle-source')
599 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
600 fdt_util.GetPhandleList(node, 'clocks'))
601 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
602
Simon Glass53af22a2018-07-17 13:25:32 -0600603 def testGetDataType(self):
604 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
605 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
606 str))
607 with self.assertRaises(ValueError) as e:
608 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
609 bool))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600610 def testFdtCellsToCpu(self):
611 val = self.node.props['intarray'].value
612 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
613 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
614
Simon Glassdff51a52021-02-03 06:00:56 -0700615 dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
Simon Glasse66d3182019-05-17 22:00:40 -0600616 node1 = dtb2.GetNode('/test1')
617 val = node1.props['reg'].value
Simon Glass2a2d91d2018-07-06 10:27:28 -0600618 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
619
Simon Glasse66d3182019-05-17 22:00:40 -0600620 node2 = dtb2.GetNode('/test2')
621 val = node2.props['reg'].value
622 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
623 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
624 2))
625 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
626
Simon Glass2a2d91d2018-07-06 10:27:28 -0600627 def testEnsureCompiled(self):
Simon Glassa004f292019-07-20 12:23:49 -0600628 """Test a degenerate case of this function (file already compiled)"""
Simon Glassdff51a52021-02-03 06:00:56 -0700629 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600630 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
631
Simon Glassa004f292019-07-20 12:23:49 -0600632 def testEnsureCompiledTmpdir(self):
633 """Test providing a temporary directory"""
634 try:
635 old_outdir = tools.outdir
636 tools.outdir= None
637 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
Simon Glassdff51a52021-02-03 06:00:56 -0700638 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
Simon Glassa004f292019-07-20 12:23:49 -0600639 tmpdir)
640 self.assertEqual(tmpdir, os.path.dirname(dtb))
641 shutil.rmtree(tmpdir)
642 finally:
643 tools.outdir= old_outdir
644
Simon Glass2a2d91d2018-07-06 10:27:28 -0600645
646def RunTestCoverage():
647 """Run the tests and check that we get 100% coverage"""
648 test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
649 ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
650
651
Simon Glass2ba98752018-07-06 10:27:24 -0600652def RunTests(args):
653 """Run all the test we have for the fdt model
654
655 Args:
656 args: List of positional args provided to fdt. This can hold a test
657 name to execute (as in 'fdt -t testFdt', for example)
658 """
659 result = unittest.TestResult()
660 sys.argv = [sys.argv[0]]
661 test_name = args and args[0] or None
Simon Glass2a2d91d2018-07-06 10:27:28 -0600662 for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
Simon Glass2ba98752018-07-06 10:27:24 -0600663 if test_name:
664 try:
665 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
666 except AttributeError:
667 continue
668 else:
669 suite = unittest.TestLoader().loadTestsFromTestCase(module)
670 suite.run(result)
671
Simon Glass90a81322019-05-17 22:00:31 -0600672 print(result)
Simon Glass2ba98752018-07-06 10:27:24 -0600673 for _, err in result.errors:
Simon Glass90a81322019-05-17 22:00:31 -0600674 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600675 for _, err in result.failures:
Simon Glass90a81322019-05-17 22:00:31 -0600676 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600677
678if __name__ != '__main__':
679 sys.exit(1)
680
681parser = OptionParser()
Simon Glass2a2d91d2018-07-06 10:27:28 -0600682parser.add_option('-B', '--build-dir', type='string', default='b',
683 help='Directory containing the build output')
Simon Glass11ae93e2018-10-01 21:12:47 -0600684parser.add_option('-P', '--processes', type=int,
685 help='set number of processes to use for running tests')
Simon Glass2ba98752018-07-06 10:27:24 -0600686parser.add_option('-t', '--test', action='store_true', dest='test',
687 default=False, help='run tests')
Simon Glass2a2d91d2018-07-06 10:27:28 -0600688parser.add_option('-T', '--test-coverage', action='store_true',
689 default=False, help='run tests and check for 100% coverage')
Simon Glass2ba98752018-07-06 10:27:24 -0600690(options, args) = parser.parse_args()
691
692# Run our meagre tests
693if options.test:
694 RunTests(args)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600695elif options.test_coverage:
696 RunTestCoverage()