blob: 1c3a8a2ab1ea192d510fc975d07a10b220ce7387 [file] [log] [blame]
Simon Glassfc017822019-10-31 07:42:54 -06001#!/usr/bin/env python3
Simon Glass0ed50752018-07-06 10:27:24 -06002# SPDX-License-Identifier: GPL-2.0+
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 Glassb8d2daa2019-07-20 12:23:49 -060010import shutil
Simon Glass0ed50752018-07-06 10:27:24 -060011import sys
Simon Glassb8d2daa2019-07-20 12:23:49 -060012import tempfile
Simon Glass0ed50752018-07-06 10:27:24 -060013import unittest
14
15# Bring in the patman libraries
16our_path = os.path.dirname(os.path.realpath(__file__))
Simon Glass42143162020-04-17 18:09:05 -060017sys.path.insert(1, os.path.join(our_path, '..'))
Simon Glass0ed50752018-07-06 10:27:24 -060018
Simon Glassa997ea52020-04-17 18:09:04 -060019from dtoc import fdt
20from dtoc import fdt_util
21from dtoc.fdt_util import fdt32_to_cpu
Simon Glassc9a032c2020-11-08 20:36:17 -070022from fdt import Type, BytesToValue
Simon Glass0ed50752018-07-06 10:27:24 -060023import libfdt
Simon Glassa997ea52020-04-17 18:09:04 -060024from patman import command
25from patman import test_util
26from patman import tools
Simon Glass0ed50752018-07-06 10:27:24 -060027
Simon Glass4df8a0c2018-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 Glass632b84c2020-11-08 20:36:20 -070049 return prop, [chr(x) for x in data]
Simon Glass4df8a0c2018-07-06 10:27:29 -060050
Simon Glass4f4b2402021-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 Glass4df8a0c2018-07-06 10:27:29 -060062
Simon Glass0ed50752018-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 Glass752e7552018-10-01 21:12:41 -060075 tools.FinaliseOutputDir()
Simon Glass0ed50752018-07-06 10:27:24 -060076
77 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -070078 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass0ed50752018-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 Glass3b9a8292019-07-20 12:23:39 -060090
Simon Glass0ed50752018-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 Glass9c526332018-07-06 10:27:28 -060094 self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
Simon Glass0ed50752018-07-06 10:27:24 -060095
Simon Glass3b9a8292019-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 Glass0ed50752018-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 Glass80d54ee2019-05-17 22:00:39 -0600103 with open(fname, 'rb') as fd:
Simon Glass0ed50752018-07-06 10:27:24 -0600104 data = fd.read()
105 os.remove(fname)
106 with self.assertRaises(IOError):
Simon Glass80d54ee2019-05-17 22:00:39 -0600107 open(fname, 'rb')
Simon Glass0ed50752018-07-06 10:27:24 -0600108 self.dtb.Flush()
Simon Glass80d54ee2019-05-17 22:00:39 -0600109 with open(fname, 'rb') as fd:
Simon Glass0ed50752018-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 Glass792d2392018-07-06 10:27:27 -0600118 self.assertTrue(isinstance(self.dtb.GetContents(), bytearray))
Simon Glass0ed50752018-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 Glass9c526332018-07-06 10:27:28 -0600125 'intarray', 'intval', 'longbytearray', 'notstring',
Simon Glass0ed50752018-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 Glass9c526332018-07-06 10:27:28 -0600132 fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
Simon Glass0ed50752018-07-06 10:27:24 -0600133 self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
134
Simon Glasse2d65282018-07-17 13:25:46 -0600135 def testGetFdt(self):
136 node = self.dtb.GetNode('/spl-test')
137 self.assertEqual(self.dtb, node.GetFdt())
Simon Glass0ed50752018-07-06 10:27:24 -0600138
Simon Glass5872f0c2019-05-17 22:00:41 -0600139 def testBytesToValue(self):
140 self.assertEqual(BytesToValue(b'this\0is\0'),
Simon Glassc9a032c2020-11-08 20:36:17 -0700141 (Type.STRING, ['this', 'is']))
Simon Glass5872f0c2019-05-17 22:00:41 -0600142
Simon Glass0ed50752018-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 Glass752e7552018-10-01 21:12:41 -0600152 tools.FinaliseOutputDir()
Simon Glass0ed50752018-07-06 10:27:24 -0600153
154 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700155 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass0ed50752018-07-06 10:27:24 -0600156 self.node = self.dtb.GetNode('/spl-test')
157
158 def testOffset(self):
159 """Tests that we can obtain the offset of a node"""
160 self.assertTrue(self.node.Offset() > 0)
161
162 def testDelete(self):
163 """Tests that we can delete a property"""
164 node2 = self.dtb.GetNode('/spl-test2')
165 offset1 = node2.Offset()
166 self.node.DeleteProp('intval')
167 offset2 = node2.Offset()
168 self.assertTrue(offset2 < offset1)
169 self.node.DeleteProp('intarray')
170 offset3 = node2.Offset()
171 self.assertTrue(offset3 < offset2)
Simon Glass9c526332018-07-06 10:27:28 -0600172 with self.assertRaises(libfdt.FdtException):
173 self.node.DeleteProp('missing')
Simon Glass0ed50752018-07-06 10:27:24 -0600174
Simon Glass4df8a0c2018-07-06 10:27:29 -0600175 def testDeleteGetOffset(self):
176 """Test that property offset update when properties are deleted"""
177 self.node.DeleteProp('intval')
178 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
179 self.assertEqual(prop.value, value)
180
Simon Glass0ed50752018-07-06 10:27:24 -0600181 def testFindNode(self):
Simon Glassaa1a5d72018-07-17 13:25:41 -0600182 """Tests that we can find a node using the FindNode() functoin"""
183 node = self.dtb.GetRoot().FindNode('i2c@0')
Simon Glass0ed50752018-07-06 10:27:24 -0600184 self.assertEqual('i2c@0', node.name)
Simon Glassaa1a5d72018-07-17 13:25:41 -0600185 subnode = node.FindNode('pmic@9')
Simon Glass0ed50752018-07-06 10:27:24 -0600186 self.assertEqual('pmic@9', subnode.name)
Simon Glassaa1a5d72018-07-17 13:25:41 -0600187 self.assertEqual(None, node.FindNode('missing'))
Simon Glass0ed50752018-07-06 10:27:24 -0600188
Simon Glass4df8a0c2018-07-06 10:27:29 -0600189 def testRefreshMissingNode(self):
190 """Test refreshing offsets when an extra node is present in dtb"""
191 # Delete it from our tables, not the device tree
192 del self.dtb._root.subnodes[-1]
193 with self.assertRaises(ValueError) as e:
194 self.dtb.Refresh()
195 self.assertIn('Internal error, offset', str(e.exception))
196
197 def testRefreshExtraNode(self):
198 """Test refreshing offsets when an expected node is missing"""
199 # Delete it from the device tre, not our tables
200 self.dtb.GetFdtObj().del_node(self.node.Offset())
201 with self.assertRaises(ValueError) as e:
202 self.dtb.Refresh()
203 self.assertIn('Internal error, node name mismatch '
204 'spl-test != spl-test2', str(e.exception))
205
206 def testRefreshMissingProp(self):
207 """Test refreshing offsets when an extra property is present in dtb"""
208 # Delete it from our tables, not the device tree
209 del self.node.props['notstring']
210 with self.assertRaises(ValueError) as e:
211 self.dtb.Refresh()
212 self.assertIn("Internal error, property 'notstring' missing, offset ",
213 str(e.exception))
214
Simon Glasse2d65282018-07-17 13:25:46 -0600215 def testLookupPhandle(self):
216 """Test looking up a single phandle"""
Simon Glass4f4b2402021-02-03 06:00:56 -0700217 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glasse2d65282018-07-17 13:25:46 -0600218 node = dtb.GetNode('/phandle-source2')
219 prop = node.props['clocks']
220 target = dtb.GetNode('/phandle-target')
221 self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
222
Simon Glass0ed50752018-07-06 10:27:24 -0600223
224class TestProp(unittest.TestCase):
225 """Test operation of the Prop class"""
226
227 @classmethod
228 def setUpClass(cls):
229 tools.PrepareOutputDir(None)
230
231 @classmethod
232 def tearDownClass(cls):
Simon Glass752e7552018-10-01 21:12:41 -0600233 tools.FinaliseOutputDir()
Simon Glass0ed50752018-07-06 10:27:24 -0600234
235 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700236 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass0ed50752018-07-06 10:27:24 -0600237 self.node = self.dtb.GetNode('/spl-test')
238 self.fdt = self.dtb.GetFdtObj()
239
Simon Glassc5eddc82018-07-06 10:27:30 -0600240 def testMissingNode(self):
241 self.assertEqual(None, self.dtb.GetNode('missing'))
242
Simon Glass9c526332018-07-06 10:27:28 -0600243 def testPhandle(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700244 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glass609e2b12018-07-06 10:27:31 -0600245 node = dtb.GetNode('/phandle-source2')
246 prop = node.props['clocks']
247 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass9c526332018-07-06 10:27:28 -0600248
249 def _ConvertProp(self, prop_name):
250 """Helper function to look up a property in self.node and return it
251
252 Args:
253 Property name to find
254
255 Return fdt.Prop object for this property
256 """
Simon Glassb474c762018-07-26 14:02:13 -0600257 p = self.fdt.getprop(self.node.Offset(), prop_name)
Simon Glass9c526332018-07-06 10:27:28 -0600258 return fdt.Prop(self.node, -1, prop_name, p)
259
260 def testMakeProp(self):
261 """Test we can convert all the the types that are supported"""
262 prop = self._ConvertProp('boolval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700263 self.assertEqual(Type.BOOL, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600264 self.assertEqual(True, prop.value)
265
266 prop = self._ConvertProp('intval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700267 self.assertEqual(Type.INT, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600268 self.assertEqual(1, fdt32_to_cpu(prop.value))
269
270 prop = self._ConvertProp('intarray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700271 self.assertEqual(Type.INT, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600272 val = [fdt32_to_cpu(val) for val in prop.value]
273 self.assertEqual([2, 3, 4], val)
274
275 prop = self._ConvertProp('byteval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700276 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600277 self.assertEqual(5, ord(prop.value))
278
279 prop = self._ConvertProp('longbytearray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700280 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600281 val = [ord(val) for val in prop.value]
282 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
283
284 prop = self._ConvertProp('stringval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700285 self.assertEqual(Type.STRING, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600286 self.assertEqual('message', prop.value)
287
288 prop = self._ConvertProp('stringarray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700289 self.assertEqual(Type.STRING, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600290 self.assertEqual(['multi-word', 'message'], prop.value)
291
292 prop = self._ConvertProp('notstring')
Simon Glassc9a032c2020-11-08 20:36:17 -0700293 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600294 val = [ord(val) for val in prop.value]
295 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
296
Simon Glass0ed50752018-07-06 10:27:24 -0600297 def testGetEmpty(self):
298 """Tests the GetEmpty() function for the various supported types"""
Simon Glassc9a032c2020-11-08 20:36:17 -0700299 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
300 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
301 self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
302 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass0ed50752018-07-06 10:27:24 -0600303
304 def testGetOffset(self):
305 """Test we can get the offset of a property"""
Simon Glass4df8a0c2018-07-06 10:27:29 -0600306 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
307 self.assertEqual(prop.value, value)
Simon Glass0ed50752018-07-06 10:27:24 -0600308
309 def testWiden(self):
310 """Test widening of values"""
311 node2 = self.dtb.GetNode('/spl-test2')
Simon Glass8034e4d2020-10-03 11:31:27 -0600312 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass0ed50752018-07-06 10:27:24 -0600313 prop = self.node.props['intval']
314
315 # No action
316 prop2 = node2.props['intval']
317 prop.Widen(prop2)
Simon Glassc9a032c2020-11-08 20:36:17 -0700318 self.assertEqual(Type.INT, prop.type)
Simon Glass0ed50752018-07-06 10:27:24 -0600319 self.assertEqual(1, fdt32_to_cpu(prop.value))
320
321 # Convert singla value to array
322 prop2 = self.node.props['intarray']
323 prop.Widen(prop2)
Simon Glassc9a032c2020-11-08 20:36:17 -0700324 self.assertEqual(Type.INT, prop.type)
Simon Glass0ed50752018-07-06 10:27:24 -0600325 self.assertTrue(isinstance(prop.value, list))
326
327 # A 4-byte array looks like a single integer. When widened by a longer
328 # byte array, it should turn into an array.
329 prop = self.node.props['longbytearray']
330 prop2 = node2.props['longbytearray']
Simon Glass8034e4d2020-10-03 11:31:27 -0600331 prop3 = node3.props['longbytearray']
Simon Glass0ed50752018-07-06 10:27:24 -0600332 self.assertFalse(isinstance(prop2.value, list))
333 self.assertEqual(4, len(prop2.value))
Simon Glass8034e4d2020-10-03 11:31:27 -0600334 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass0ed50752018-07-06 10:27:24 -0600335 prop2.Widen(prop)
336 self.assertTrue(isinstance(prop2.value, list))
337 self.assertEqual(9, len(prop2.value))
Simon Glass8034e4d2020-10-03 11:31:27 -0600338 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
339 '\0', '\0', '\0', '\0'], prop2.value)
340 prop3.Widen(prop)
341 self.assertTrue(isinstance(prop3.value, list))
342 self.assertEqual(9, len(prop3.value))
343 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
344 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass0ed50752018-07-06 10:27:24 -0600345
346 # Similarly for a string array
347 prop = self.node.props['stringval']
348 prop2 = node2.props['stringarray']
349 self.assertFalse(isinstance(prop.value, list))
350 self.assertEqual(7, len(prop.value))
351 prop.Widen(prop2)
352 self.assertTrue(isinstance(prop.value, list))
353 self.assertEqual(3, len(prop.value))
354
355 # Enlarging an existing array
356 prop = self.node.props['stringarray']
357 prop2 = node2.props['stringarray']
358 self.assertTrue(isinstance(prop.value, list))
359 self.assertEqual(2, len(prop.value))
360 prop.Widen(prop2)
361 self.assertTrue(isinstance(prop.value, list))
362 self.assertEqual(3, len(prop.value))
363
Simon Glasse80c5562018-07-06 10:27:38 -0600364 def testAdd(self):
365 """Test adding properties"""
366 self.fdt.pack()
367 # This function should automatically expand the device tree
368 self.node.AddZeroProp('one')
369 self.node.AddZeroProp('two')
370 self.node.AddZeroProp('three')
Simon Glasseddd7292018-09-14 04:57:13 -0600371 self.dtb.Sync(auto_resize=True)
Simon Glasse80c5562018-07-06 10:27:38 -0600372
373 # Updating existing properties should be OK, since the device-tree size
374 # does not change
375 self.fdt.pack()
376 self.node.SetInt('one', 1)
377 self.node.SetInt('two', 2)
378 self.node.SetInt('three', 3)
Simon Glasseddd7292018-09-14 04:57:13 -0600379 self.dtb.Sync(auto_resize=False)
Simon Glasse80c5562018-07-06 10:27:38 -0600380
381 # This should fail since it would need to increase the device-tree size
Simon Glasseddd7292018-09-14 04:57:13 -0600382 self.node.AddZeroProp('four')
Simon Glasse80c5562018-07-06 10:27:38 -0600383 with self.assertRaises(libfdt.FdtException) as e:
Simon Glasseddd7292018-09-14 04:57:13 -0600384 self.dtb.Sync(auto_resize=False)
Simon Glasse80c5562018-07-06 10:27:38 -0600385 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
Simon Glassccd25262018-09-14 04:57:16 -0600386 self.dtb.Sync(auto_resize=True)
Simon Glasse80c5562018-07-06 10:27:38 -0600387
Simon Glasseddd7292018-09-14 04:57:13 -0600388 def testAddNode(self):
389 self.fdt.pack()
Simon Glassf3a17962018-09-14 04:57:15 -0600390 self.node.AddSubnode('subnode')
391 with self.assertRaises(libfdt.FdtException) as e:
392 self.dtb.Sync(auto_resize=False)
393 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
394
395 self.dtb.Sync(auto_resize=True)
396 offset = self.fdt.path_offset('/spl-test/subnode')
397 self.assertTrue(offset > 0)
Simon Glasseddd7292018-09-14 04:57:13 -0600398
Simon Glassccd25262018-09-14 04:57:16 -0600399 def testAddMore(self):
400 """Test various other methods for adding and setting properties"""
401 self.node.AddZeroProp('one')
402 self.dtb.Sync(auto_resize=True)
403 data = self.fdt.getprop(self.node.Offset(), 'one')
404 self.assertEqual(0, fdt32_to_cpu(data))
405
406 self.node.SetInt('one', 1)
407 self.dtb.Sync(auto_resize=False)
408 data = self.fdt.getprop(self.node.Offset(), 'one')
409 self.assertEqual(1, fdt32_to_cpu(data))
410
Simon Glassa2af7302021-01-06 21:35:18 -0700411 val = 1234
412 self.node.AddInt('integer', val)
413 self.dtb.Sync(auto_resize=True)
414 data = self.fdt.getprop(self.node.Offset(), 'integer')
415 self.assertEqual(val, fdt32_to_cpu(data))
416
Simon Glassccd25262018-09-14 04:57:16 -0600417 val = '123' + chr(0) + '456'
418 self.node.AddString('string', val)
419 self.dtb.Sync(auto_resize=True)
420 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glass1cd40082019-05-17 22:00:36 -0600421 self.assertEqual(tools.ToBytes(val) + b'\0', data)
Simon Glassccd25262018-09-14 04:57:16 -0600422
423 self.fdt.pack()
424 self.node.SetString('string', val + 'x')
425 with self.assertRaises(libfdt.FdtException) as e:
426 self.dtb.Sync(auto_resize=False)
427 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
428 self.node.SetString('string', val[:-1])
429
430 prop = self.node.props['string']
Simon Glass1cd40082019-05-17 22:00:36 -0600431 prop.SetData(tools.ToBytes(val))
Simon Glassccd25262018-09-14 04:57:16 -0600432 self.dtb.Sync(auto_resize=False)
433 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glass1cd40082019-05-17 22:00:36 -0600434 self.assertEqual(tools.ToBytes(val), data)
Simon Glassccd25262018-09-14 04:57:16 -0600435
436 self.node.AddEmptyProp('empty', 5)
437 self.dtb.Sync(auto_resize=True)
438 prop = self.node.props['empty']
Simon Glass1cd40082019-05-17 22:00:36 -0600439 prop.SetData(tools.ToBytes(val))
Simon Glassccd25262018-09-14 04:57:16 -0600440 self.dtb.Sync(auto_resize=False)
441 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glass1cd40082019-05-17 22:00:36 -0600442 self.assertEqual(tools.ToBytes(val), data)
Simon Glassccd25262018-09-14 04:57:16 -0600443
Simon Glass1cd40082019-05-17 22:00:36 -0600444 self.node.SetData('empty', b'123')
445 self.assertEqual(b'123', prop.bytes)
Simon Glassccd25262018-09-14 04:57:16 -0600446
Simon Glassf67c99c2020-07-09 18:39:44 -0600447 # Trying adding a lot of data at once
448 self.node.AddData('data', tools.GetBytes(65, 20000))
449 self.dtb.Sync(auto_resize=True)
450
Simon Glassb8a49292018-09-14 04:57:17 -0600451 def testFromData(self):
452 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
453 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
454
455 self.node.AddEmptyProp('empty', 5)
456 self.dtb.Sync(auto_resize=True)
457 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
458
Simon Glassa683a5f2019-07-20 12:23:37 -0600459 def testMissingSetInt(self):
460 """Test handling of a missing property with SetInt"""
461 with self.assertRaises(ValueError) as e:
462 self.node.SetInt('one', 1)
463 self.assertIn("node '/spl-test': Missing property 'one'",
464 str(e.exception))
465
466 def testMissingSetData(self):
467 """Test handling of a missing property with SetData"""
468 with self.assertRaises(ValueError) as e:
469 self.node.SetData('one', b'data')
470 self.assertIn("node '/spl-test': Missing property 'one'",
471 str(e.exception))
472
473 def testMissingSetString(self):
474 """Test handling of a missing property with SetString"""
475 with self.assertRaises(ValueError) as e:
476 self.node.SetString('one', 1)
477 self.assertIn("node '/spl-test': Missing property 'one'",
478 str(e.exception))
479
Simon Glass74f5feb2019-07-20 12:24:08 -0600480 def testGetFilename(self):
481 """Test the dtb filename can be provided"""
482 self.assertEqual(tools.GetOutputFilename('source.dtb'),
483 self.dtb.GetFilename())
484
Simon Glass0ed50752018-07-06 10:27:24 -0600485
Simon Glass9c526332018-07-06 10:27:28 -0600486class TestFdtUtil(unittest.TestCase):
487 """Tests for the fdt_util module
488
489 This module will likely be mostly replaced at some point, once upstream
490 libfdt has better Python support. For now, this provides tests for current
491 functionality.
492 """
493 @classmethod
494 def setUpClass(cls):
495 tools.PrepareOutputDir(None)
496
Simon Glass752e7552018-10-01 21:12:41 -0600497 @classmethod
498 def tearDownClass(cls):
499 tools.FinaliseOutputDir()
500
Simon Glass9c526332018-07-06 10:27:28 -0600501 def setUp(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700502 self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass9c526332018-07-06 10:27:28 -0600503 self.node = self.dtb.GetNode('/spl-test')
504
505 def testGetInt(self):
506 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
507 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
508
509 with self.assertRaises(ValueError) as e:
510 self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
511 self.assertIn("property 'intarray' has list value: expecting a single "
512 'integer', str(e.exception))
513
514 def testGetString(self):
515 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
516 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
517 'test'))
518
519 with self.assertRaises(ValueError) as e:
520 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
521 self.assertIn("property 'stringarray' has list value: expecting a "
522 'single string', str(e.exception))
523
524 def testGetBool(self):
525 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
526 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
527 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
528 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
529
Simon Glass53f53992018-07-17 13:25:40 -0600530 def testGetByte(self):
531 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
532 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
533
534 with self.assertRaises(ValueError) as e:
535 fdt_util.GetByte(self.node, 'longbytearray')
536 self.assertIn("property 'longbytearray' has list value: expecting a "
537 'single byte', str(e.exception))
538
539 with self.assertRaises(ValueError) as e:
540 fdt_util.GetByte(self.node, 'intval')
541 self.assertIn("property 'intval' has length 4, expecting 1",
542 str(e.exception))
543
Simon Glasse2d65282018-07-17 13:25:46 -0600544 def testGetPhandleList(self):
Simon Glass4f4b2402021-02-03 06:00:56 -0700545 dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
Simon Glasse2d65282018-07-17 13:25:46 -0600546 node = dtb.GetNode('/phandle-source2')
547 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
548 node = dtb.GetNode('/phandle-source')
549 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
550 fdt_util.GetPhandleList(node, 'clocks'))
551 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
552
Simon Glass91710b32018-07-17 13:25:32 -0600553 def testGetDataType(self):
554 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
555 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
556 str))
557 with self.assertRaises(ValueError) as e:
558 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
559 bool))
Simon Glass9c526332018-07-06 10:27:28 -0600560 def testFdtCellsToCpu(self):
561 val = self.node.props['intarray'].value
562 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
563 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
564
Simon Glass4f4b2402021-02-03 06:00:56 -0700565 dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
Simon Glassb0a34a42019-05-17 22:00:40 -0600566 node1 = dtb2.GetNode('/test1')
567 val = node1.props['reg'].value
Simon Glass9c526332018-07-06 10:27:28 -0600568 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
569
Simon Glassb0a34a42019-05-17 22:00:40 -0600570 node2 = dtb2.GetNode('/test2')
571 val = node2.props['reg'].value
572 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
573 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
574 2))
575 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
576
Simon Glass9c526332018-07-06 10:27:28 -0600577 def testEnsureCompiled(self):
Simon Glassb8d2daa2019-07-20 12:23:49 -0600578 """Test a degenerate case of this function (file already compiled)"""
Simon Glass4f4b2402021-02-03 06:00:56 -0700579 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
Simon Glass9c526332018-07-06 10:27:28 -0600580 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
581
Simon Glassb8d2daa2019-07-20 12:23:49 -0600582 def testEnsureCompiledTmpdir(self):
583 """Test providing a temporary directory"""
584 try:
585 old_outdir = tools.outdir
586 tools.outdir= None
587 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
Simon Glass4f4b2402021-02-03 06:00:56 -0700588 dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
Simon Glassb8d2daa2019-07-20 12:23:49 -0600589 tmpdir)
590 self.assertEqual(tmpdir, os.path.dirname(dtb))
591 shutil.rmtree(tmpdir)
592 finally:
593 tools.outdir= old_outdir
594
Simon Glass9c526332018-07-06 10:27:28 -0600595
596def RunTestCoverage():
597 """Run the tests and check that we get 100% coverage"""
598 test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
599 ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
600
601
Simon Glass0ed50752018-07-06 10:27:24 -0600602def RunTests(args):
603 """Run all the test we have for the fdt model
604
605 Args:
606 args: List of positional args provided to fdt. This can hold a test
607 name to execute (as in 'fdt -t testFdt', for example)
608 """
609 result = unittest.TestResult()
610 sys.argv = [sys.argv[0]]
611 test_name = args and args[0] or None
Simon Glass9c526332018-07-06 10:27:28 -0600612 for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
Simon Glass0ed50752018-07-06 10:27:24 -0600613 if test_name:
614 try:
615 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
616 except AttributeError:
617 continue
618 else:
619 suite = unittest.TestLoader().loadTestsFromTestCase(module)
620 suite.run(result)
621
Simon Glass61b88e52019-05-17 22:00:31 -0600622 print(result)
Simon Glass0ed50752018-07-06 10:27:24 -0600623 for _, err in result.errors:
Simon Glass61b88e52019-05-17 22:00:31 -0600624 print(err)
Simon Glass0ed50752018-07-06 10:27:24 -0600625 for _, err in result.failures:
Simon Glass61b88e52019-05-17 22:00:31 -0600626 print(err)
Simon Glass0ed50752018-07-06 10:27:24 -0600627
628if __name__ != '__main__':
629 sys.exit(1)
630
631parser = OptionParser()
Simon Glass9c526332018-07-06 10:27:28 -0600632parser.add_option('-B', '--build-dir', type='string', default='b',
633 help='Directory containing the build output')
Simon Glass7057d022018-10-01 21:12:47 -0600634parser.add_option('-P', '--processes', type=int,
635 help='set number of processes to use for running tests')
Simon Glass0ed50752018-07-06 10:27:24 -0600636parser.add_option('-t', '--test', action='store_true', dest='test',
637 default=False, help='run tests')
Simon Glass9c526332018-07-06 10:27:28 -0600638parser.add_option('-T', '--test-coverage', action='store_true',
639 default=False, help='run tests and check for 100% coverage')
Simon Glass0ed50752018-07-06 10:27:24 -0600640(options, args) = parser.parse_args()
641
642# Run our meagre tests
643if options.test:
644 RunTests(args)
Simon Glass9c526332018-07-06 10:27:28 -0600645elif options.test_coverage:
646 RunTestCoverage()