blob: 1e66e1bc3533ddefbd3e3a480ac845ad2132e8a5 [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
240 # Add a property to the node after i2c@0 to check that this is not
241 # disturbed by adding a subnode to i2c@0
242 orig_node = self.dtb.GetNode('/orig-node')
243 orig_node.AddInt('integer-4', 456)
244
245 # Add a property to the pmic node to check that pmic properties are not
246 # disturbed
247 pmic = self.dtb.GetNode('/i2c@0/pmic@9')
248 pmic.AddInt('integer-5', 567)
249
250 self.dtb.Sync(auto_resize=True)
251
Simon Glass2ba98752018-07-06 10:27:24 -0600252
253class TestProp(unittest.TestCase):
254 """Test operation of the Prop class"""
255
256 @classmethod
257 def setUpClass(cls):
258 tools.PrepareOutputDir(None)
259
260 @classmethod
261 def tearDownClass(cls):
Simon Glasse0e62752018-10-01 21:12:41 -0600262 tools.FinaliseOutputDir()
Simon Glass2ba98752018-07-06 10:27:24 -0600263
264 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700265 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2ba98752018-07-06 10:27:24 -0600266 self.node = self.dtb.GetNode('/spl-test')
267 self.fdt = self.dtb.GetFdtObj()
268
Simon Glassb9066ff2018-07-06 10:27:30 -0600269 def testMissingNode(self):
270 self.assertEqual(None, self.dtb.GetNode('missing'))
271
Simon Glass2a2d91d2018-07-06 10:27:28 -0600272 def testPhandle(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700273 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass760b7172018-07-06 10:27:31 -0600274 node = dtb.GetNode('/phandle-source2')
275 prop = node.props['clocks']
276 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600277
278 def _ConvertProp(self, prop_name):
279 """Helper function to look up a property in self.node and return it
280
281 Args:
282 Property name to find
283
284 Return fdt.Prop object for this property
285 """
Simon Glass50c59522018-07-26 14:02:13 -0600286 p = self.fdt.getprop(self.node.Offset(), prop_name)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600287 return fdt.Prop(self.node, -1, prop_name, p)
288
289 def testMakeProp(self):
290 """Test we can convert all the the types that are supported"""
291 prop = self._ConvertProp('boolval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700292 self.assertEqual(Type.BOOL, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600293 self.assertEqual(True, prop.value)
294
295 prop = self._ConvertProp('intval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700296 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600297 self.assertEqual(1, fdt32_to_cpu(prop.value))
298
299 prop = self._ConvertProp('intarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700300 self.assertEqual(Type.INT, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600301 val = [fdt32_to_cpu(val) for val in prop.value]
302 self.assertEqual([2, 3, 4], val)
303
304 prop = self._ConvertProp('byteval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700305 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600306 self.assertEqual(5, ord(prop.value))
307
308 prop = self._ConvertProp('longbytearray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700309 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600310 val = [ord(val) for val in prop.value]
311 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
312
313 prop = self._ConvertProp('stringval')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700314 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600315 self.assertEqual('message', prop.value)
316
317 prop = self._ConvertProp('stringarray')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700318 self.assertEqual(Type.STRING, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600319 self.assertEqual(['multi-word', 'message'], prop.value)
320
321 prop = self._ConvertProp('notstring')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700322 self.assertEqual(Type.BYTE, prop.type)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600323 val = [ord(val) for val in prop.value]
324 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
325
Simon Glass2ba98752018-07-06 10:27:24 -0600326 def testGetEmpty(self):
327 """Tests the GetEmpty() function for the various supported types"""
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700328 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
329 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
330 self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
331 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass2ba98752018-07-06 10:27:24 -0600332
333 def testGetOffset(self):
334 """Test we can get the offset of a property"""
Simon Glassf9b88b32018-07-06 10:27:29 -0600335 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
336 self.assertEqual(prop.value, value)
Simon Glass2ba98752018-07-06 10:27:24 -0600337
338 def testWiden(self):
339 """Test widening of values"""
340 node2 = self.dtb.GetNode('/spl-test2')
Simon Glasse144caf2020-10-03 11:31:27 -0600341 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass2ba98752018-07-06 10:27:24 -0600342 prop = self.node.props['intval']
343
344 # No action
345 prop2 = node2.props['intval']
346 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700347 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600348 self.assertEqual(1, fdt32_to_cpu(prop.value))
349
350 # Convert singla value to array
351 prop2 = self.node.props['intarray']
352 prop.Widen(prop2)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700353 self.assertEqual(Type.INT, prop.type)
Simon Glass2ba98752018-07-06 10:27:24 -0600354 self.assertTrue(isinstance(prop.value, list))
355
356 # A 4-byte array looks like a single integer. When widened by a longer
357 # byte array, it should turn into an array.
358 prop = self.node.props['longbytearray']
359 prop2 = node2.props['longbytearray']
Simon Glasse144caf2020-10-03 11:31:27 -0600360 prop3 = node3.props['longbytearray']
Simon Glass2ba98752018-07-06 10:27:24 -0600361 self.assertFalse(isinstance(prop2.value, list))
362 self.assertEqual(4, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600363 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600364 prop2.Widen(prop)
365 self.assertTrue(isinstance(prop2.value, list))
366 self.assertEqual(9, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600367 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
368 '\0', '\0', '\0', '\0'], prop2.value)
369 prop3.Widen(prop)
370 self.assertTrue(isinstance(prop3.value, list))
371 self.assertEqual(9, len(prop3.value))
372 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
373 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600374
375 # Similarly for a string array
376 prop = self.node.props['stringval']
377 prop2 = node2.props['stringarray']
378 self.assertFalse(isinstance(prop.value, list))
379 self.assertEqual(7, len(prop.value))
380 prop.Widen(prop2)
381 self.assertTrue(isinstance(prop.value, list))
382 self.assertEqual(3, len(prop.value))
383
384 # Enlarging an existing array
385 prop = self.node.props['stringarray']
386 prop2 = node2.props['stringarray']
387 self.assertTrue(isinstance(prop.value, list))
388 self.assertEqual(2, len(prop.value))
389 prop.Widen(prop2)
390 self.assertTrue(isinstance(prop.value, list))
391 self.assertEqual(3, len(prop.value))
392
Simon Glass116adec2018-07-06 10:27:38 -0600393 def testAdd(self):
394 """Test adding properties"""
395 self.fdt.pack()
396 # This function should automatically expand the device tree
397 self.node.AddZeroProp('one')
398 self.node.AddZeroProp('two')
399 self.node.AddZeroProp('three')
Simon Glassfa80c252018-09-14 04:57:13 -0600400 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600401
402 # Updating existing properties should be OK, since the device-tree size
403 # does not change
404 self.fdt.pack()
405 self.node.SetInt('one', 1)
406 self.node.SetInt('two', 2)
407 self.node.SetInt('three', 3)
Simon Glassfa80c252018-09-14 04:57:13 -0600408 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600409
410 # This should fail since it would need to increase the device-tree size
Simon Glassfa80c252018-09-14 04:57:13 -0600411 self.node.AddZeroProp('four')
Simon Glass116adec2018-07-06 10:27:38 -0600412 with self.assertRaises(libfdt.FdtException) as e:
Simon Glassfa80c252018-09-14 04:57:13 -0600413 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600414 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
Simon Glass64349612018-09-14 04:57:16 -0600415 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600416
Simon Glass64349612018-09-14 04:57:16 -0600417 def testAddMore(self):
418 """Test various other methods for adding and setting properties"""
419 self.node.AddZeroProp('one')
420 self.dtb.Sync(auto_resize=True)
421 data = self.fdt.getprop(self.node.Offset(), 'one')
422 self.assertEqual(0, fdt32_to_cpu(data))
423
424 self.node.SetInt('one', 1)
425 self.dtb.Sync(auto_resize=False)
426 data = self.fdt.getprop(self.node.Offset(), 'one')
427 self.assertEqual(1, fdt32_to_cpu(data))
428
Simon Glass6eb99322021-01-06 21:35:18 -0700429 val = 1234
430 self.node.AddInt('integer', val)
431 self.dtb.Sync(auto_resize=True)
432 data = self.fdt.getprop(self.node.Offset(), 'integer')
433 self.assertEqual(val, fdt32_to_cpu(data))
434
Simon Glass64349612018-09-14 04:57:16 -0600435 val = '123' + chr(0) + '456'
436 self.node.AddString('string', val)
437 self.dtb.Sync(auto_resize=True)
438 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600439 self.assertEqual(tools.ToBytes(val) + b'\0', data)
Simon Glass64349612018-09-14 04:57:16 -0600440
441 self.fdt.pack()
442 self.node.SetString('string', val + 'x')
443 with self.assertRaises(libfdt.FdtException) as e:
444 self.dtb.Sync(auto_resize=False)
445 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
446 self.node.SetString('string', val[:-1])
447
448 prop = self.node.props['string']
Simon Glassf6b64812019-05-17 22:00:36 -0600449 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600450 self.dtb.Sync(auto_resize=False)
451 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600452 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600453
454 self.node.AddEmptyProp('empty', 5)
455 self.dtb.Sync(auto_resize=True)
456 prop = self.node.props['empty']
Simon Glassf6b64812019-05-17 22:00:36 -0600457 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600458 self.dtb.Sync(auto_resize=False)
459 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glassf6b64812019-05-17 22:00:36 -0600460 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600461
Simon Glassf6b64812019-05-17 22:00:36 -0600462 self.node.SetData('empty', b'123')
463 self.assertEqual(b'123', prop.bytes)
Simon Glass64349612018-09-14 04:57:16 -0600464
Simon Glassc0639172020-07-09 18:39:44 -0600465 # Trying adding a lot of data at once
466 self.node.AddData('data', tools.GetBytes(65, 20000))
467 self.dtb.Sync(auto_resize=True)
468
Simon Glass746aee32018-09-14 04:57:17 -0600469 def testFromData(self):
470 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
471 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
472
473 self.node.AddEmptyProp('empty', 5)
474 self.dtb.Sync(auto_resize=True)
475 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
476
Simon Glassd9dad102019-07-20 12:23:37 -0600477 def testMissingSetInt(self):
478 """Test handling of a missing property with SetInt"""
479 with self.assertRaises(ValueError) as e:
480 self.node.SetInt('one', 1)
481 self.assertIn("node '/spl-test': Missing property 'one'",
482 str(e.exception))
483
484 def testMissingSetData(self):
485 """Test handling of a missing property with SetData"""
486 with self.assertRaises(ValueError) as e:
487 self.node.SetData('one', b'data')
488 self.assertIn("node '/spl-test': Missing property 'one'",
489 str(e.exception))
490
491 def testMissingSetString(self):
492 """Test handling of a missing property with SetString"""
493 with self.assertRaises(ValueError) as e:
494 self.node.SetString('one', 1)
495 self.assertIn("node '/spl-test': Missing property 'one'",
496 str(e.exception))
497
Simon Glassf6e02492019-07-20 12:24:08 -0600498 def testGetFilename(self):
499 """Test the dtb filename can be provided"""
500 self.assertEqual(tools.GetOutputFilename('source.dtb'),
501 self.dtb.GetFilename())
502
Simon Glass2ba98752018-07-06 10:27:24 -0600503
Simon Glass2a2d91d2018-07-06 10:27:28 -0600504class TestFdtUtil(unittest.TestCase):
505 """Tests for the fdt_util module
506
507 This module will likely be mostly replaced at some point, once upstream
508 libfdt has better Python support. For now, this provides tests for current
509 functionality.
510 """
511 @classmethod
512 def setUpClass(cls):
513 tools.PrepareOutputDir(None)
514
Simon Glasse0e62752018-10-01 21:12:41 -0600515 @classmethod
516 def tearDownClass(cls):
517 tools.FinaliseOutputDir()
518
Simon Glass2a2d91d2018-07-06 10:27:28 -0600519 def setUp(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700520 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600521 self.node = self.dtb.GetNode('/spl-test')
522
523 def testGetInt(self):
524 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
525 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
526
527 with self.assertRaises(ValueError) as e:
528 self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
529 self.assertIn("property 'intarray' has list value: expecting a single "
530 'integer', str(e.exception))
531
532 def testGetString(self):
533 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
534 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
535 'test'))
536
537 with self.assertRaises(ValueError) as e:
538 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
539 self.assertIn("property 'stringarray' has list value: expecting a "
540 'single string', str(e.exception))
541
542 def testGetBool(self):
543 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
544 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
545 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
546 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
547
Simon Glass3af8e492018-07-17 13:25:40 -0600548 def testGetByte(self):
549 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
550 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
551
552 with self.assertRaises(ValueError) as e:
553 fdt_util.GetByte(self.node, 'longbytearray')
554 self.assertIn("property 'longbytearray' has list value: expecting a "
555 'single byte', str(e.exception))
556
557 with self.assertRaises(ValueError) as e:
558 fdt_util.GetByte(self.node, 'intval')
559 self.assertIn("property 'intval' has length 4, expecting 1",
560 str(e.exception))
561
Simon Glass94a7c602018-07-17 13:25:46 -0600562 def testGetPhandleList(self):
Simon Glassdff51a52021-02-03 06:00:56 -0700563 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass94a7c602018-07-17 13:25:46 -0600564 node = dtb.GetNode('/phandle-source2')
565 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
566 node = dtb.GetNode('/phandle-source')
567 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
568 fdt_util.GetPhandleList(node, 'clocks'))
569 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
570
Simon Glass53af22a2018-07-17 13:25:32 -0600571 def testGetDataType(self):
572 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
573 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
574 str))
575 with self.assertRaises(ValueError) as e:
576 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
577 bool))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600578 def testFdtCellsToCpu(self):
579 val = self.node.props['intarray'].value
580 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
581 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
582
Simon Glassdff51a52021-02-03 06:00:56 -0700583 dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
Simon Glasse66d3182019-05-17 22:00:40 -0600584 node1 = dtb2.GetNode('/test1')
585 val = node1.props['reg'].value
Simon Glass2a2d91d2018-07-06 10:27:28 -0600586 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
587
Simon Glasse66d3182019-05-17 22:00:40 -0600588 node2 = dtb2.GetNode('/test2')
589 val = node2.props['reg'].value
590 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
591 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
592 2))
593 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
594
Simon Glass2a2d91d2018-07-06 10:27:28 -0600595 def testEnsureCompiled(self):
Simon Glassa004f292019-07-20 12:23:49 -0600596 """Test a degenerate case of this function (file already compiled)"""
Simon Glassdff51a52021-02-03 06:00:56 -0700597 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600598 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
599
Simon Glassa004f292019-07-20 12:23:49 -0600600 def testEnsureCompiledTmpdir(self):
601 """Test providing a temporary directory"""
602 try:
603 old_outdir = tools.outdir
604 tools.outdir= None
605 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
Simon Glassdff51a52021-02-03 06:00:56 -0700606 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
Simon Glassa004f292019-07-20 12:23:49 -0600607 tmpdir)
608 self.assertEqual(tmpdir, os.path.dirname(dtb))
609 shutil.rmtree(tmpdir)
610 finally:
611 tools.outdir= old_outdir
612
Simon Glass2a2d91d2018-07-06 10:27:28 -0600613
614def RunTestCoverage():
615 """Run the tests and check that we get 100% coverage"""
616 test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
617 ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
618
619
Simon Glass2ba98752018-07-06 10:27:24 -0600620def RunTests(args):
621 """Run all the test we have for the fdt model
622
623 Args:
624 args: List of positional args provided to fdt. This can hold a test
625 name to execute (as in 'fdt -t testFdt', for example)
626 """
627 result = unittest.TestResult()
628 sys.argv = [sys.argv[0]]
629 test_name = args and args[0] or None
Simon Glass2a2d91d2018-07-06 10:27:28 -0600630 for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
Simon Glass2ba98752018-07-06 10:27:24 -0600631 if test_name:
632 try:
633 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
634 except AttributeError:
635 continue
636 else:
637 suite = unittest.TestLoader().loadTestsFromTestCase(module)
638 suite.run(result)
639
Simon Glass90a81322019-05-17 22:00:31 -0600640 print(result)
Simon Glass2ba98752018-07-06 10:27:24 -0600641 for _, err in result.errors:
Simon Glass90a81322019-05-17 22:00:31 -0600642 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600643 for _, err in result.failures:
Simon Glass90a81322019-05-17 22:00:31 -0600644 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600645
646if __name__ != '__main__':
647 sys.exit(1)
648
649parser = OptionParser()
Simon Glass2a2d91d2018-07-06 10:27:28 -0600650parser.add_option('-B', '--build-dir', type='string', default='b',
651 help='Directory containing the build output')
Simon Glass11ae93e2018-10-01 21:12:47 -0600652parser.add_option('-P', '--processes', type=int,
653 help='set number of processes to use for running tests')
Simon Glass2ba98752018-07-06 10:27:24 -0600654parser.add_option('-t', '--test', action='store_true', dest='test',
655 default=False, help='run tests')
Simon Glass2a2d91d2018-07-06 10:27:28 -0600656parser.add_option('-T', '--test-coverage', action='store_true',
657 default=False, help='run tests and check for 100% coverage')
Simon Glass2ba98752018-07-06 10:27:24 -0600658(options, args) = parser.parse_args()
659
660# Run our meagre tests
661if options.test:
662 RunTests(args)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600663elif options.test_coverage:
664 RunTestCoverage()