blob: 49a2853f07f5fbfedf25e5da9ed4d171785c37c3 [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 Glass2ba98752018-07-06 10:27:24 -0600268
269class TestProp(unittest.TestCase):
270 """Test operation of the Prop class"""
271
272 @classmethod
273 def setUpClass(cls):
274 tools.PrepareOutputDir(None)
275
276 @classmethod
277 def tearDownClass(cls):
Simon Glasse0e62752018-10-01 21:12:41 -0600278 tools.FinaliseOutputDir()
Simon Glass2ba98752018-07-06 10:27:24 -0600279
280 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700281 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -0600282 self.node = self.dtb.GetNode('/spl-test')
283 self.fdt = self.dtb.GetFdtObj()
284
Simon Glassb9066ff2018-07-06 10:27:30 -0600285 def testMissingNode(self):
286 self.assertEqual(None, self.dtb.GetNode('missing'))
287
Simon Glass2a2d91d2018-07-06 10:27:28 -0600288 def testPhandle(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700289 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass760b7172018-07-06 10:27:31 -0600290 node = dtb.GetNode('/phandle-source2')
291 prop = node.props['clocks']
292 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600293
294 def _ConvertProp(self, prop_name):
295 """Helper function to look up a property in self.node and return it
296
297 Args:
298 Property name to find
299
300 Return fdt.Prop object for this property
301 """
Simon Glass50c59522018-07-26 14:02:13 -0600302 p = self.fdt.getprop(self.node.Offset(), prop_name)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600303 return fdt.Prop(self.node, -1, prop_name, p)
304
305 def testMakeProp(self):
306 """Test we can convert all the the types that are supported"""
307 prop = self._ConvertProp('boolval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700308 self.assertEqual(Type.BOOL, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600309 self.assertEqual(True, prop.value)
310
311 prop = self._ConvertProp('intval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700312 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600313 self.assertEqual(1, fdt32_to_cpu(prop.value))
314
315 prop = self._ConvertProp('intarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700316 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600317 val = [fdt32_to_cpu(val) for val in prop.value]
318 self.assertEqual([2, 3, 4], val)
319
320 prop = self._ConvertProp('byteval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700321 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600322 self.assertEqual(5, ord(prop.value))
323
324 prop = self._ConvertProp('longbytearray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700325 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600326 val = [ord(val) for val in prop.value]
327 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
328
329 prop = self._ConvertProp('stringval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700330 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600331 self.assertEqual('message', prop.value)
332
333 prop = self._ConvertProp('stringarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700334 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600335 self.assertEqual(['multi-word', 'message'], prop.value)
336
337 prop = self._ConvertProp('notstring')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700338 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600339 val = [ord(val) for val in prop.value]
340 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
341
Simon Glass2ba98752018-07-06 10:27:24 -0600342 def testGetEmpty(self):
343 """Tests the GetEmpty() function for the various supported types"""
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700344 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
345 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
346 self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
347 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass2ba98752018-07-06 10:27:24 -0600348
349 def testGetOffset(self):
350 """Test we can get the offset of a property"""
Simon Glassf9b88b32018-07-06 10:27:29 -0600351 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
352 self.assertEqual(prop.value, value)
Simon Glass2ba98752018-07-06 10:27:24 -0600353
354 def testWiden(self):
355 """Test widening of values"""
356 node2 = self.dtb.GetNode('/spl-test2')
Simon Glasse144caf2020-10-03 11:31:27 -0600357 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass2ba98752018-07-06 10:27:24 -0600358 prop = self.node.props['intval']
359
360 # No action
361 prop2 = node2.props['intval']
362 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700363 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600364 self.assertEqual(1, fdt32_to_cpu(prop.value))
365
366 # Convert singla value to array
367 prop2 = self.node.props['intarray']
368 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700369 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600370 self.assertTrue(isinstance(prop.value, list))
371
372 # A 4-byte array looks like a single integer. When widened by a longer
373 # byte array, it should turn into an array.
374 prop = self.node.props['longbytearray']
375 prop2 = node2.props['longbytearray']
Simon Glasse144caf2020-10-03 11:31:27 -0600376 prop3 = node3.props['longbytearray']
Simon Glass2ba98752018-07-06 10:27:24 -0600377 self.assertFalse(isinstance(prop2.value, list))
378 self.assertEqual(4, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600379 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600380 prop2.Widen(prop)
381 self.assertTrue(isinstance(prop2.value, list))
382 self.assertEqual(9, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600383 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
384 '\0', '\0', '\0', '\0'], prop2.value)
385 prop3.Widen(prop)
386 self.assertTrue(isinstance(prop3.value, list))
387 self.assertEqual(9, len(prop3.value))
388 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
389 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600390
391 # Similarly for a string array
392 prop = self.node.props['stringval']
393 prop2 = node2.props['stringarray']
394 self.assertFalse(isinstance(prop.value, list))
395 self.assertEqual(7, len(prop.value))
396 prop.Widen(prop2)
397 self.assertTrue(isinstance(prop.value, list))
398 self.assertEqual(3, len(prop.value))
399
400 # Enlarging an existing array
401 prop = self.node.props['stringarray']
402 prop2 = node2.props['stringarray']
403 self.assertTrue(isinstance(prop.value, list))
404 self.assertEqual(2, len(prop.value))
405 prop.Widen(prop2)
406 self.assertTrue(isinstance(prop.value, list))
407 self.assertEqual(3, len(prop.value))
408
Simon Glass116adec2018-07-06 10:27:38 -0600409 def testAdd(self):
410 """Test adding properties"""
411 self.fdt.pack()
412 # This function should automatically expand the device tree
413 self.node.AddZeroProp('one')
414 self.node.AddZeroProp('two')
415 self.node.AddZeroProp('three')
Simon Glassfa80c252018-09-14 04:57:13 -0600416 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600417
418 # Updating existing properties should be OK, since the device-tree size
419 # does not change
420 self.fdt.pack()
421 self.node.SetInt('one', 1)
422 self.node.SetInt('two', 2)
423 self.node.SetInt('three', 3)
Simon Glassfa80c252018-09-14 04:57:13 -0600424 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600425
426 # This should fail since it would need to increase the device-tree size
Simon Glassfa80c252018-09-14 04:57:13 -0600427 self.node.AddZeroProp('four')
Simon Glass116adec2018-07-06 10:27:38 -0600428 with self.assertRaises(libfdt.FdtException) as e:
Simon Glassfa80c252018-09-14 04:57:13 -0600429 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600430 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
Simon Glass64349612018-09-14 04:57:16 -0600431 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600432
Simon Glass64349612018-09-14 04:57:16 -0600433 def testAddMore(self):
434 """Test various other methods for adding and setting properties"""
435 self.node.AddZeroProp('one')
436 self.dtb.Sync(auto_resize=True)
437 data = self.fdt.getprop(self.node.Offset(), 'one')
438 self.assertEqual(0, fdt32_to_cpu(data))
439
440 self.node.SetInt('one', 1)
441 self.dtb.Sync(auto_resize=False)
442 data = self.fdt.getprop(self.node.Offset(), 'one')
443 self.assertEqual(1, fdt32_to_cpu(data))
444
Simon Glass6eb99322021-01-06 21:35:18 -0700445 val = 1234
446 self.node.AddInt('integer', val)
447 self.dtb.Sync(auto_resize=True)
448 data = self.fdt.getprop(self.node.Offset(), 'integer')
449 self.assertEqual(val, fdt32_to_cpu(data))
450
Simon Glass64349612018-09-14 04:57:16 -0600451 val = '123' + chr(0) + '456'
452 self.node.AddString('string', val)
453 self.dtb.Sync(auto_resize=True)
454 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600455 self.assertEqual(tools.ToBytes(val) + b'\0', data)
Simon Glass64349612018-09-14 04:57:16 -0600456
457 self.fdt.pack()
458 self.node.SetString('string', val + 'x')
459 with self.assertRaises(libfdt.FdtException) as e:
460 self.dtb.Sync(auto_resize=False)
461 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
462 self.node.SetString('string', val[:-1])
463
464 prop = self.node.props['string']
Simon Glassf6b64812019-05-17 22:00:36 -0600465 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600466 self.dtb.Sync(auto_resize=False)
467 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600468 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600469
470 self.node.AddEmptyProp('empty', 5)
471 self.dtb.Sync(auto_resize=True)
472 prop = self.node.props['empty']
Simon Glassf6b64812019-05-17 22:00:36 -0600473 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600474 self.dtb.Sync(auto_resize=False)
475 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glassf6b64812019-05-17 22:00:36 -0600476 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600477
Simon Glassf6b64812019-05-17 22:00:36 -0600478 self.node.SetData('empty', b'123')
479 self.assertEqual(b'123', prop.bytes)
Simon Glass64349612018-09-14 04:57:16 -0600480
Simon Glassc0639172020-07-09 18:39:44 -0600481 # Trying adding a lot of data at once
482 self.node.AddData('data', tools.GetBytes(65, 20000))
483 self.dtb.Sync(auto_resize=True)
484
Simon Glass746aee32018-09-14 04:57:17 -0600485 def testFromData(self):
486 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
487 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
488
489 self.node.AddEmptyProp('empty', 5)
490 self.dtb.Sync(auto_resize=True)
491 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
492
Simon Glassd9dad102019-07-20 12:23:37 -0600493 def testMissingSetInt(self):
494 """Test handling of a missing property with SetInt"""
495 with self.assertRaises(ValueError) as e:
496 self.node.SetInt('one', 1)
497 self.assertIn("node '/spl-test': Missing property 'one'",
498 str(e.exception))
499
500 def testMissingSetData(self):
501 """Test handling of a missing property with SetData"""
502 with self.assertRaises(ValueError) as e:
503 self.node.SetData('one', b'data')
504 self.assertIn("node '/spl-test': Missing property 'one'",
505 str(e.exception))
506
507 def testMissingSetString(self):
508 """Test handling of a missing property with SetString"""
509 with self.assertRaises(ValueError) as e:
510 self.node.SetString('one', 1)
511 self.assertIn("node '/spl-test': Missing property 'one'",
512 str(e.exception))
513
Simon Glassf6e02492019-07-20 12:24:08 -0600514 def testGetFilename(self):
515 """Test the dtb filename can be provided"""
516 self.assertEqual(tools.GetOutputFilename('source.dtb'),
517 self.dtb.GetFilename())
518
Simon Glass2ba98752018-07-06 10:27:24 -0600519
Simon Glass2a2d91d2018-07-06 10:27:28 -0600520class TestFdtUtil(unittest.TestCase):
521 """Tests for the fdt_util module
522
523 This module will likely be mostly replaced at some point, once upstream
524 libfdt has better Python support. For now, this provides tests for current
525 functionality.
526 """
527 @classmethod
528 def setUpClass(cls):
529 tools.PrepareOutputDir(None)
530
Simon Glasse0e62752018-10-01 21:12:41 -0600531 @classmethod
532 def tearDownClass(cls):
533 tools.FinaliseOutputDir()
534
Simon Glass2a2d91d2018-07-06 10:27:28 -0600535 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700536 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600537 self.node = self.dtb.GetNode('/spl-test')
538
539 def testGetInt(self):
540 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
541 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
542
543 with self.assertRaises(ValueError) as e:
544 self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
545 self.assertIn("property 'intarray' has list value: expecting a single "
546 'integer', str(e.exception))
547
548 def testGetString(self):
549 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
550 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
551 'test'))
552
553 with self.assertRaises(ValueError) as e:
554 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
555 self.assertIn("property 'stringarray' has list value: expecting a "
556 'single string', str(e.exception))
557
558 def testGetBool(self):
559 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
560 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
561 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
562 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
563
Simon Glass3af8e492018-07-17 13:25:40 -0600564 def testGetByte(self):
565 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
566 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
567
568 with self.assertRaises(ValueError) as e:
569 fdt_util.GetByte(self.node, 'longbytearray')
570 self.assertIn("property 'longbytearray' has list value: expecting a "
571 'single byte', str(e.exception))
572
573 with self.assertRaises(ValueError) as e:
574 fdt_util.GetByte(self.node, 'intval')
575 self.assertIn("property 'intval' has length 4, expecting 1",
576 str(e.exception))
577
Simon Glass94a7c602018-07-17 13:25:46 -0600578 def testGetPhandleList(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700579 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass94a7c602018-07-17 13:25:46 -0600580 node = dtb.GetNode('/phandle-source2')
581 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
582 node = dtb.GetNode('/phandle-source')
583 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
584 fdt_util.GetPhandleList(node, 'clocks'))
585 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
586
Simon Glass53af22a2018-07-17 13:25:32 -0600587 def testGetDataType(self):
588 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
589 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
590 str))
591 with self.assertRaises(ValueError) as e:
592 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
593 bool))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600594 def testFdtCellsToCpu(self):
595 val = self.node.props['intarray'].value
596 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
597 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
598
Simon Glassdff51a52021-02-03 06:00:56 -0700599 dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
Simon Glasse66d3182019-05-17 22:00:40 -0600600 node1 = dtb2.GetNode('/test1')
601 val = node1.props['reg'].value
Simon Glass2a2d91d2018-07-06 10:27:28 -0600602 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
603
Simon Glasse66d3182019-05-17 22:00:40 -0600604 node2 = dtb2.GetNode('/test2')
605 val = node2.props['reg'].value
606 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
607 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
608 2))
609 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
610
Simon Glass2a2d91d2018-07-06 10:27:28 -0600611 def testEnsureCompiled(self):
Simon Glassa004f292019-07-20 12:23:49 -0600612 """Test a degenerate case of this function (file already compiled)"""
Simon Glassdff51a52021-02-03 06:00:56 -0700613 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600614 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
615
Simon Glassa004f292019-07-20 12:23:49 -0600616 def testEnsureCompiledTmpdir(self):
617 """Test providing a temporary directory"""
618 try:
619 old_outdir = tools.outdir
620 tools.outdir= None
621 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
Simon Glassdff51a52021-02-03 06:00:56 -0700622 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
Simon Glassa004f292019-07-20 12:23:49 -0600623 tmpdir)
624 self.assertEqual(tmpdir, os.path.dirname(dtb))
625 shutil.rmtree(tmpdir)
626 finally:
627 tools.outdir= old_outdir
628
Simon Glass2a2d91d2018-07-06 10:27:28 -0600629
630def RunTestCoverage():
631 """Run the tests and check that we get 100% coverage"""
632 test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
633 ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
634
635
Simon Glass2ba98752018-07-06 10:27:24 -0600636def RunTests(args):
637 """Run all the test we have for the fdt model
638
639 Args:
640 args: List of positional args provided to fdt. This can hold a test
641 name to execute (as in 'fdt -t testFdt', for example)
642 """
643 result = unittest.TestResult()
644 sys.argv = [sys.argv[0]]
645 test_name = args and args[0] or None
Simon Glass2a2d91d2018-07-06 10:27:28 -0600646 for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
Simon Glass2ba98752018-07-06 10:27:24 -0600647 if test_name:
648 try:
649 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
650 except AttributeError:
651 continue
652 else:
653 suite = unittest.TestLoader().loadTestsFromTestCase(module)
654 suite.run(result)
655
Simon Glass90a81322019-05-17 22:00:31 -0600656 print(result)
Simon Glass2ba98752018-07-06 10:27:24 -0600657 for _, err in result.errors:
Simon Glass90a81322019-05-17 22:00:31 -0600658 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600659 for _, err in result.failures:
Simon Glass90a81322019-05-17 22:00:31 -0600660 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600661
662if __name__ != '__main__':
663 sys.exit(1)
664
665parser = OptionParser()
Simon Glass2a2d91d2018-07-06 10:27:28 -0600666parser.add_option('-B', '--build-dir', type='string', default='b',
667 help='Directory containing the build output')
Simon Glass11ae93e2018-10-01 21:12:47 -0600668parser.add_option('-P', '--processes', type=int,
669 help='set number of processes to use for running tests')
Simon Glass2ba98752018-07-06 10:27:24 -0600670parser.add_option('-t', '--test', action='store_true', dest='test',
671 default=False, help='run tests')
Simon Glass2a2d91d2018-07-06 10:27:28 -0600672parser.add_option('-T', '--test-coverage', action='store_true',
673 default=False, help='run tests and check for 100% coverage')
Simon Glass2ba98752018-07-06 10:27:24 -0600674(options, args) = parser.parse_args()
675
676# Run our meagre tests
677if options.test:
678 RunTests(args)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600679elif options.test_coverage:
680 RunTestCoverage()