blob: e8fbbd5d10aa987e40a85d33221dd3fcea2b144e [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
51
Simon Glass0ed50752018-07-06 10:27:24 -060052class TestFdt(unittest.TestCase):
53 """Tests for the Fdt module
54
55 This includes unit tests for some functions and functional tests for the fdt
56 module.
57 """
58 @classmethod
59 def setUpClass(cls):
60 tools.PrepareOutputDir(None)
61
62 @classmethod
63 def tearDownClass(cls):
Simon Glass752e7552018-10-01 21:12:41 -060064 tools.FinaliseOutputDir()
Simon Glass0ed50752018-07-06 10:27:24 -060065
66 def setUp(self):
67 self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
68
69 def testFdt(self):
70 """Test that we can open an Fdt"""
71 self.dtb.Scan()
72 root = self.dtb.GetRoot()
73 self.assertTrue(isinstance(root, fdt.Node))
74
75 def testGetNode(self):
76 """Test the GetNode() method"""
77 node = self.dtb.GetNode('/spl-test')
78 self.assertTrue(isinstance(node, fdt.Node))
Simon Glass3b9a8292019-07-20 12:23:39 -060079
Simon Glass0ed50752018-07-06 10:27:24 -060080 node = self.dtb.GetNode('/i2c@0/pmic@9')
81 self.assertTrue(isinstance(node, fdt.Node))
82 self.assertEqual('pmic@9', node.name)
Simon Glass9c526332018-07-06 10:27:28 -060083 self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
Simon Glass0ed50752018-07-06 10:27:24 -060084
Simon Glass3b9a8292019-07-20 12:23:39 -060085 node = self.dtb.GetNode('/')
86 self.assertTrue(isinstance(node, fdt.Node))
87 self.assertEqual(0, node.Offset())
88
Simon Glass0ed50752018-07-06 10:27:24 -060089 def testFlush(self):
90 """Check that we can flush the device tree out to its file"""
91 fname = self.dtb._fname
Simon Glass80d54ee2019-05-17 22:00:39 -060092 with open(fname, 'rb') as fd:
Simon Glass0ed50752018-07-06 10:27:24 -060093 data = fd.read()
94 os.remove(fname)
95 with self.assertRaises(IOError):
Simon Glass80d54ee2019-05-17 22:00:39 -060096 open(fname, 'rb')
Simon Glass0ed50752018-07-06 10:27:24 -060097 self.dtb.Flush()
Simon Glass80d54ee2019-05-17 22:00:39 -060098 with open(fname, 'rb') as fd:
Simon Glass0ed50752018-07-06 10:27:24 -060099 data = fd.read()
100
101 def testPack(self):
102 """Test that packing a device tree works"""
103 self.dtb.Pack()
104
105 def testGetFdt(self):
106 """Tetst that we can access the raw device-tree data"""
Simon Glass792d2392018-07-06 10:27:27 -0600107 self.assertTrue(isinstance(self.dtb.GetContents(), bytearray))
Simon Glass0ed50752018-07-06 10:27:24 -0600108
109 def testGetProps(self):
110 """Tests obtaining a list of properties"""
111 node = self.dtb.GetNode('/spl-test')
112 props = self.dtb.GetProps(node)
113 self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
Simon Glass9c526332018-07-06 10:27:28 -0600114 'intarray', 'intval', 'longbytearray', 'notstring',
Simon Glass0ed50752018-07-06 10:27:24 -0600115 'stringarray', 'stringval', 'u-boot,dm-pre-reloc'],
116 sorted(props.keys()))
117
118 def testCheckError(self):
119 """Tests the ChecKError() function"""
120 with self.assertRaises(ValueError) as e:
Simon Glass9c526332018-07-06 10:27:28 -0600121 fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
Simon Glass0ed50752018-07-06 10:27:24 -0600122 self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
123
Simon Glasse2d65282018-07-17 13:25:46 -0600124 def testGetFdt(self):
125 node = self.dtb.GetNode('/spl-test')
126 self.assertEqual(self.dtb, node.GetFdt())
Simon Glass0ed50752018-07-06 10:27:24 -0600127
Simon Glass5872f0c2019-05-17 22:00:41 -0600128 def testBytesToValue(self):
129 self.assertEqual(BytesToValue(b'this\0is\0'),
Simon Glassc9a032c2020-11-08 20:36:17 -0700130 (Type.STRING, ['this', 'is']))
Simon Glass5872f0c2019-05-17 22:00:41 -0600131
Simon Glass0ed50752018-07-06 10:27:24 -0600132class TestNode(unittest.TestCase):
133 """Test operation of the Node class"""
134
135 @classmethod
136 def setUpClass(cls):
137 tools.PrepareOutputDir(None)
138
139 @classmethod
140 def tearDownClass(cls):
Simon Glass752e7552018-10-01 21:12:41 -0600141 tools.FinaliseOutputDir()
Simon Glass0ed50752018-07-06 10:27:24 -0600142
143 def setUp(self):
144 self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
145 self.node = self.dtb.GetNode('/spl-test')
146
147 def testOffset(self):
148 """Tests that we can obtain the offset of a node"""
149 self.assertTrue(self.node.Offset() > 0)
150
151 def testDelete(self):
152 """Tests that we can delete a property"""
153 node2 = self.dtb.GetNode('/spl-test2')
154 offset1 = node2.Offset()
155 self.node.DeleteProp('intval')
156 offset2 = node2.Offset()
157 self.assertTrue(offset2 < offset1)
158 self.node.DeleteProp('intarray')
159 offset3 = node2.Offset()
160 self.assertTrue(offset3 < offset2)
Simon Glass9c526332018-07-06 10:27:28 -0600161 with self.assertRaises(libfdt.FdtException):
162 self.node.DeleteProp('missing')
Simon Glass0ed50752018-07-06 10:27:24 -0600163
Simon Glass4df8a0c2018-07-06 10:27:29 -0600164 def testDeleteGetOffset(self):
165 """Test that property offset update when properties are deleted"""
166 self.node.DeleteProp('intval')
167 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
168 self.assertEqual(prop.value, value)
169
Simon Glass0ed50752018-07-06 10:27:24 -0600170 def testFindNode(self):
Simon Glassaa1a5d72018-07-17 13:25:41 -0600171 """Tests that we can find a node using the FindNode() functoin"""
172 node = self.dtb.GetRoot().FindNode('i2c@0')
Simon Glass0ed50752018-07-06 10:27:24 -0600173 self.assertEqual('i2c@0', node.name)
Simon Glassaa1a5d72018-07-17 13:25:41 -0600174 subnode = node.FindNode('pmic@9')
Simon Glass0ed50752018-07-06 10:27:24 -0600175 self.assertEqual('pmic@9', subnode.name)
Simon Glassaa1a5d72018-07-17 13:25:41 -0600176 self.assertEqual(None, node.FindNode('missing'))
Simon Glass0ed50752018-07-06 10:27:24 -0600177
Simon Glass4df8a0c2018-07-06 10:27:29 -0600178 def testRefreshMissingNode(self):
179 """Test refreshing offsets when an extra node is present in dtb"""
180 # Delete it from our tables, not the device tree
181 del self.dtb._root.subnodes[-1]
182 with self.assertRaises(ValueError) as e:
183 self.dtb.Refresh()
184 self.assertIn('Internal error, offset', str(e.exception))
185
186 def testRefreshExtraNode(self):
187 """Test refreshing offsets when an expected node is missing"""
188 # Delete it from the device tre, not our tables
189 self.dtb.GetFdtObj().del_node(self.node.Offset())
190 with self.assertRaises(ValueError) as e:
191 self.dtb.Refresh()
192 self.assertIn('Internal error, node name mismatch '
193 'spl-test != spl-test2', str(e.exception))
194
195 def testRefreshMissingProp(self):
196 """Test refreshing offsets when an extra property is present in dtb"""
197 # Delete it from our tables, not the device tree
198 del self.node.props['notstring']
199 with self.assertRaises(ValueError) as e:
200 self.dtb.Refresh()
201 self.assertIn("Internal error, property 'notstring' missing, offset ",
202 str(e.exception))
203
Simon Glasse2d65282018-07-17 13:25:46 -0600204 def testLookupPhandle(self):
205 """Test looking up a single phandle"""
206 dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
207 node = dtb.GetNode('/phandle-source2')
208 prop = node.props['clocks']
209 target = dtb.GetNode('/phandle-target')
210 self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
211
Simon Glass0ed50752018-07-06 10:27:24 -0600212
213class TestProp(unittest.TestCase):
214 """Test operation of the Prop class"""
215
216 @classmethod
217 def setUpClass(cls):
218 tools.PrepareOutputDir(None)
219
220 @classmethod
221 def tearDownClass(cls):
Simon Glass752e7552018-10-01 21:12:41 -0600222 tools.FinaliseOutputDir()
Simon Glass0ed50752018-07-06 10:27:24 -0600223
224 def setUp(self):
225 self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
226 self.node = self.dtb.GetNode('/spl-test')
227 self.fdt = self.dtb.GetFdtObj()
228
Simon Glassc5eddc82018-07-06 10:27:30 -0600229 def testMissingNode(self):
230 self.assertEqual(None, self.dtb.GetNode('missing'))
231
Simon Glass9c526332018-07-06 10:27:28 -0600232 def testPhandle(self):
233 dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
Simon Glass609e2b12018-07-06 10:27:31 -0600234 node = dtb.GetNode('/phandle-source2')
235 prop = node.props['clocks']
236 self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Simon Glass9c526332018-07-06 10:27:28 -0600237
238 def _ConvertProp(self, prop_name):
239 """Helper function to look up a property in self.node and return it
240
241 Args:
242 Property name to find
243
244 Return fdt.Prop object for this property
245 """
Simon Glassb474c762018-07-26 14:02:13 -0600246 p = self.fdt.getprop(self.node.Offset(), prop_name)
Simon Glass9c526332018-07-06 10:27:28 -0600247 return fdt.Prop(self.node, -1, prop_name, p)
248
249 def testMakeProp(self):
250 """Test we can convert all the the types that are supported"""
251 prop = self._ConvertProp('boolval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700252 self.assertEqual(Type.BOOL, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600253 self.assertEqual(True, prop.value)
254
255 prop = self._ConvertProp('intval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700256 self.assertEqual(Type.INT, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600257 self.assertEqual(1, fdt32_to_cpu(prop.value))
258
259 prop = self._ConvertProp('intarray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700260 self.assertEqual(Type.INT, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600261 val = [fdt32_to_cpu(val) for val in prop.value]
262 self.assertEqual([2, 3, 4], val)
263
264 prop = self._ConvertProp('byteval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700265 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600266 self.assertEqual(5, ord(prop.value))
267
268 prop = self._ConvertProp('longbytearray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700269 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600270 val = [ord(val) for val in prop.value]
271 self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
272
273 prop = self._ConvertProp('stringval')
Simon Glassc9a032c2020-11-08 20:36:17 -0700274 self.assertEqual(Type.STRING, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600275 self.assertEqual('message', prop.value)
276
277 prop = self._ConvertProp('stringarray')
Simon Glassc9a032c2020-11-08 20:36:17 -0700278 self.assertEqual(Type.STRING, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600279 self.assertEqual(['multi-word', 'message'], prop.value)
280
281 prop = self._ConvertProp('notstring')
Simon Glassc9a032c2020-11-08 20:36:17 -0700282 self.assertEqual(Type.BYTE, prop.type)
Simon Glass9c526332018-07-06 10:27:28 -0600283 val = [ord(val) for val in prop.value]
284 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
285
Simon Glass0ed50752018-07-06 10:27:24 -0600286 def testGetEmpty(self):
287 """Tests the GetEmpty() function for the various supported types"""
Simon Glassc9a032c2020-11-08 20:36:17 -0700288 self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
289 self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
290 self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
291 self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
Simon Glass0ed50752018-07-06 10:27:24 -0600292
293 def testGetOffset(self):
294 """Test we can get the offset of a property"""
Simon Glass4df8a0c2018-07-06 10:27:29 -0600295 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
296 self.assertEqual(prop.value, value)
Simon Glass0ed50752018-07-06 10:27:24 -0600297
298 def testWiden(self):
299 """Test widening of values"""
300 node2 = self.dtb.GetNode('/spl-test2')
Simon Glass8034e4d2020-10-03 11:31:27 -0600301 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass0ed50752018-07-06 10:27:24 -0600302 prop = self.node.props['intval']
303
304 # No action
305 prop2 = node2.props['intval']
306 prop.Widen(prop2)
Simon Glassc9a032c2020-11-08 20:36:17 -0700307 self.assertEqual(Type.INT, prop.type)
Simon Glass0ed50752018-07-06 10:27:24 -0600308 self.assertEqual(1, fdt32_to_cpu(prop.value))
309
310 # Convert singla value to array
311 prop2 = self.node.props['intarray']
312 prop.Widen(prop2)
Simon Glassc9a032c2020-11-08 20:36:17 -0700313 self.assertEqual(Type.INT, prop.type)
Simon Glass0ed50752018-07-06 10:27:24 -0600314 self.assertTrue(isinstance(prop.value, list))
315
316 # A 4-byte array looks like a single integer. When widened by a longer
317 # byte array, it should turn into an array.
318 prop = self.node.props['longbytearray']
319 prop2 = node2.props['longbytearray']
Simon Glass8034e4d2020-10-03 11:31:27 -0600320 prop3 = node3.props['longbytearray']
Simon Glass0ed50752018-07-06 10:27:24 -0600321 self.assertFalse(isinstance(prop2.value, list))
322 self.assertEqual(4, len(prop2.value))
Simon Glass8034e4d2020-10-03 11:31:27 -0600323 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass0ed50752018-07-06 10:27:24 -0600324 prop2.Widen(prop)
325 self.assertTrue(isinstance(prop2.value, list))
326 self.assertEqual(9, len(prop2.value))
Simon Glass8034e4d2020-10-03 11:31:27 -0600327 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
328 '\0', '\0', '\0', '\0'], prop2.value)
329 prop3.Widen(prop)
330 self.assertTrue(isinstance(prop3.value, list))
331 self.assertEqual(9, len(prop3.value))
332 self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
333 '\x0e', '\x0f', '\x10', '\0'], prop3.value)
Simon Glass0ed50752018-07-06 10:27:24 -0600334
335 # Similarly for a string array
336 prop = self.node.props['stringval']
337 prop2 = node2.props['stringarray']
338 self.assertFalse(isinstance(prop.value, list))
339 self.assertEqual(7, len(prop.value))
340 prop.Widen(prop2)
341 self.assertTrue(isinstance(prop.value, list))
342 self.assertEqual(3, len(prop.value))
343
344 # Enlarging an existing array
345 prop = self.node.props['stringarray']
346 prop2 = node2.props['stringarray']
347 self.assertTrue(isinstance(prop.value, list))
348 self.assertEqual(2, len(prop.value))
349 prop.Widen(prop2)
350 self.assertTrue(isinstance(prop.value, list))
351 self.assertEqual(3, len(prop.value))
352
Simon Glasse80c5562018-07-06 10:27:38 -0600353 def testAdd(self):
354 """Test adding properties"""
355 self.fdt.pack()
356 # This function should automatically expand the device tree
357 self.node.AddZeroProp('one')
358 self.node.AddZeroProp('two')
359 self.node.AddZeroProp('three')
Simon Glasseddd7292018-09-14 04:57:13 -0600360 self.dtb.Sync(auto_resize=True)
Simon Glasse80c5562018-07-06 10:27:38 -0600361
362 # Updating existing properties should be OK, since the device-tree size
363 # does not change
364 self.fdt.pack()
365 self.node.SetInt('one', 1)
366 self.node.SetInt('two', 2)
367 self.node.SetInt('three', 3)
Simon Glasseddd7292018-09-14 04:57:13 -0600368 self.dtb.Sync(auto_resize=False)
Simon Glasse80c5562018-07-06 10:27:38 -0600369
370 # This should fail since it would need to increase the device-tree size
Simon Glasseddd7292018-09-14 04:57:13 -0600371 self.node.AddZeroProp('four')
Simon Glasse80c5562018-07-06 10:27:38 -0600372 with self.assertRaises(libfdt.FdtException) as e:
Simon Glasseddd7292018-09-14 04:57:13 -0600373 self.dtb.Sync(auto_resize=False)
Simon Glasse80c5562018-07-06 10:27:38 -0600374 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
Simon Glassccd25262018-09-14 04:57:16 -0600375 self.dtb.Sync(auto_resize=True)
Simon Glasse80c5562018-07-06 10:27:38 -0600376
Simon Glasseddd7292018-09-14 04:57:13 -0600377 def testAddNode(self):
378 self.fdt.pack()
Simon Glassf3a17962018-09-14 04:57:15 -0600379 self.node.AddSubnode('subnode')
380 with self.assertRaises(libfdt.FdtException) as e:
381 self.dtb.Sync(auto_resize=False)
382 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
383
384 self.dtb.Sync(auto_resize=True)
385 offset = self.fdt.path_offset('/spl-test/subnode')
386 self.assertTrue(offset > 0)
Simon Glasseddd7292018-09-14 04:57:13 -0600387
Simon Glassccd25262018-09-14 04:57:16 -0600388 def testAddMore(self):
389 """Test various other methods for adding and setting properties"""
390 self.node.AddZeroProp('one')
391 self.dtb.Sync(auto_resize=True)
392 data = self.fdt.getprop(self.node.Offset(), 'one')
393 self.assertEqual(0, fdt32_to_cpu(data))
394
395 self.node.SetInt('one', 1)
396 self.dtb.Sync(auto_resize=False)
397 data = self.fdt.getprop(self.node.Offset(), 'one')
398 self.assertEqual(1, fdt32_to_cpu(data))
399
Simon Glassa2af7302021-01-06 21:35:18 -0700400 val = 1234
401 self.node.AddInt('integer', val)
402 self.dtb.Sync(auto_resize=True)
403 data = self.fdt.getprop(self.node.Offset(), 'integer')
404 self.assertEqual(val, fdt32_to_cpu(data))
405
Simon Glassccd25262018-09-14 04:57:16 -0600406 val = '123' + chr(0) + '456'
407 self.node.AddString('string', val)
408 self.dtb.Sync(auto_resize=True)
409 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glass1cd40082019-05-17 22:00:36 -0600410 self.assertEqual(tools.ToBytes(val) + b'\0', data)
Simon Glassccd25262018-09-14 04:57:16 -0600411
412 self.fdt.pack()
413 self.node.SetString('string', val + 'x')
414 with self.assertRaises(libfdt.FdtException) as e:
415 self.dtb.Sync(auto_resize=False)
416 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
417 self.node.SetString('string', val[:-1])
418
419 prop = self.node.props['string']
Simon Glass1cd40082019-05-17 22:00:36 -0600420 prop.SetData(tools.ToBytes(val))
Simon Glassccd25262018-09-14 04:57:16 -0600421 self.dtb.Sync(auto_resize=False)
422 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glass1cd40082019-05-17 22:00:36 -0600423 self.assertEqual(tools.ToBytes(val), data)
Simon Glassccd25262018-09-14 04:57:16 -0600424
425 self.node.AddEmptyProp('empty', 5)
426 self.dtb.Sync(auto_resize=True)
427 prop = self.node.props['empty']
Simon Glass1cd40082019-05-17 22:00:36 -0600428 prop.SetData(tools.ToBytes(val))
Simon Glassccd25262018-09-14 04:57:16 -0600429 self.dtb.Sync(auto_resize=False)
430 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glass1cd40082019-05-17 22:00:36 -0600431 self.assertEqual(tools.ToBytes(val), data)
Simon Glassccd25262018-09-14 04:57:16 -0600432
Simon Glass1cd40082019-05-17 22:00:36 -0600433 self.node.SetData('empty', b'123')
434 self.assertEqual(b'123', prop.bytes)
Simon Glassccd25262018-09-14 04:57:16 -0600435
Simon Glassf67c99c2020-07-09 18:39:44 -0600436 # Trying adding a lot of data at once
437 self.node.AddData('data', tools.GetBytes(65, 20000))
438 self.dtb.Sync(auto_resize=True)
439
Simon Glassb8a49292018-09-14 04:57:17 -0600440 def testFromData(self):
441 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
442 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
443
444 self.node.AddEmptyProp('empty', 5)
445 self.dtb.Sync(auto_resize=True)
446 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
447
Simon Glassa683a5f2019-07-20 12:23:37 -0600448 def testMissingSetInt(self):
449 """Test handling of a missing property with SetInt"""
450 with self.assertRaises(ValueError) as e:
451 self.node.SetInt('one', 1)
452 self.assertIn("node '/spl-test': Missing property 'one'",
453 str(e.exception))
454
455 def testMissingSetData(self):
456 """Test handling of a missing property with SetData"""
457 with self.assertRaises(ValueError) as e:
458 self.node.SetData('one', b'data')
459 self.assertIn("node '/spl-test': Missing property 'one'",
460 str(e.exception))
461
462 def testMissingSetString(self):
463 """Test handling of a missing property with SetString"""
464 with self.assertRaises(ValueError) as e:
465 self.node.SetString('one', 1)
466 self.assertIn("node '/spl-test': Missing property 'one'",
467 str(e.exception))
468
Simon Glass74f5feb2019-07-20 12:24:08 -0600469 def testGetFilename(self):
470 """Test the dtb filename can be provided"""
471 self.assertEqual(tools.GetOutputFilename('source.dtb'),
472 self.dtb.GetFilename())
473
Simon Glass0ed50752018-07-06 10:27:24 -0600474
Simon Glass9c526332018-07-06 10:27:28 -0600475class TestFdtUtil(unittest.TestCase):
476 """Tests for the fdt_util module
477
478 This module will likely be mostly replaced at some point, once upstream
479 libfdt has better Python support. For now, this provides tests for current
480 functionality.
481 """
482 @classmethod
483 def setUpClass(cls):
484 tools.PrepareOutputDir(None)
485
Simon Glass752e7552018-10-01 21:12:41 -0600486 @classmethod
487 def tearDownClass(cls):
488 tools.FinaliseOutputDir()
489
Simon Glass9c526332018-07-06 10:27:28 -0600490 def setUp(self):
491 self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
492 self.node = self.dtb.GetNode('/spl-test')
493
494 def testGetInt(self):
495 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
496 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
497
498 with self.assertRaises(ValueError) as e:
499 self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
500 self.assertIn("property 'intarray' has list value: expecting a single "
501 'integer', str(e.exception))
502
503 def testGetString(self):
504 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
505 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
506 'test'))
507
508 with self.assertRaises(ValueError) as e:
509 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
510 self.assertIn("property 'stringarray' has list value: expecting a "
511 'single string', str(e.exception))
512
513 def testGetBool(self):
514 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
515 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
516 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
517 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
518
Simon Glass53f53992018-07-17 13:25:40 -0600519 def testGetByte(self):
520 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
521 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
522
523 with self.assertRaises(ValueError) as e:
524 fdt_util.GetByte(self.node, 'longbytearray')
525 self.assertIn("property 'longbytearray' has list value: expecting a "
526 'single byte', str(e.exception))
527
528 with self.assertRaises(ValueError) as e:
529 fdt_util.GetByte(self.node, 'intval')
530 self.assertIn("property 'intval' has length 4, expecting 1",
531 str(e.exception))
532
Simon Glasse2d65282018-07-17 13:25:46 -0600533 def testGetPhandleList(self):
534 dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
535 node = dtb.GetNode('/phandle-source2')
536 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
537 node = dtb.GetNode('/phandle-source')
538 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
539 fdt_util.GetPhandleList(node, 'clocks'))
540 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
541
Simon Glass91710b32018-07-17 13:25:32 -0600542 def testGetDataType(self):
543 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
544 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
545 str))
546 with self.assertRaises(ValueError) as e:
547 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
548 bool))
Simon Glass9c526332018-07-06 10:27:28 -0600549 def testFdtCellsToCpu(self):
550 val = self.node.props['intarray'].value
551 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
552 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
553
554 dtb2 = fdt.FdtScan('tools/dtoc/dtoc_test_addr64.dts')
Simon Glassb0a34a42019-05-17 22:00:40 -0600555 node1 = dtb2.GetNode('/test1')
556 val = node1.props['reg'].value
Simon Glass9c526332018-07-06 10:27:28 -0600557 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
558
Simon Glassb0a34a42019-05-17 22:00:40 -0600559 node2 = dtb2.GetNode('/test2')
560 val = node2.props['reg'].value
561 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
562 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
563 2))
564 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
565
Simon Glass9c526332018-07-06 10:27:28 -0600566 def testEnsureCompiled(self):
Simon Glassb8d2daa2019-07-20 12:23:49 -0600567 """Test a degenerate case of this function (file already compiled)"""
Simon Glass9c526332018-07-06 10:27:28 -0600568 dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
569 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
570
Simon Glassb8d2daa2019-07-20 12:23:49 -0600571 def testEnsureCompiledTmpdir(self):
572 """Test providing a temporary directory"""
573 try:
574 old_outdir = tools.outdir
575 tools.outdir= None
576 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
577 dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts',
578 tmpdir)
579 self.assertEqual(tmpdir, os.path.dirname(dtb))
580 shutil.rmtree(tmpdir)
581 finally:
582 tools.outdir= old_outdir
583
Simon Glass9c526332018-07-06 10:27:28 -0600584
585def RunTestCoverage():
586 """Run the tests and check that we get 100% coverage"""
587 test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
588 ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
589
590
Simon Glass0ed50752018-07-06 10:27:24 -0600591def RunTests(args):
592 """Run all the test we have for the fdt model
593
594 Args:
595 args: List of positional args provided to fdt. This can hold a test
596 name to execute (as in 'fdt -t testFdt', for example)
597 """
598 result = unittest.TestResult()
599 sys.argv = [sys.argv[0]]
600 test_name = args and args[0] or None
Simon Glass9c526332018-07-06 10:27:28 -0600601 for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
Simon Glass0ed50752018-07-06 10:27:24 -0600602 if test_name:
603 try:
604 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
605 except AttributeError:
606 continue
607 else:
608 suite = unittest.TestLoader().loadTestsFromTestCase(module)
609 suite.run(result)
610
Simon Glass61b88e52019-05-17 22:00:31 -0600611 print(result)
Simon Glass0ed50752018-07-06 10:27:24 -0600612 for _, err in result.errors:
Simon Glass61b88e52019-05-17 22:00:31 -0600613 print(err)
Simon Glass0ed50752018-07-06 10:27:24 -0600614 for _, err in result.failures:
Simon Glass61b88e52019-05-17 22:00:31 -0600615 print(err)
Simon Glass0ed50752018-07-06 10:27:24 -0600616
617if __name__ != '__main__':
618 sys.exit(1)
619
620parser = OptionParser()
Simon Glass9c526332018-07-06 10:27:28 -0600621parser.add_option('-B', '--build-dir', type='string', default='b',
622 help='Directory containing the build output')
Simon Glass7057d022018-10-01 21:12:47 -0600623parser.add_option('-P', '--processes', type=int,
624 help='set number of processes to use for running tests')
Simon Glass0ed50752018-07-06 10:27:24 -0600625parser.add_option('-t', '--test', action='store_true', dest='test',
626 default=False, help='run tests')
Simon Glass9c526332018-07-06 10:27:28 -0600627parser.add_option('-T', '--test-coverage', action='store_true',
628 default=False, help='run tests and check for 100% coverage')
Simon Glass0ed50752018-07-06 10:27:24 -0600629(options, args) = parser.parse_args()
630
631# Run our meagre tests
632if options.test:
633 RunTests(args)
Simon Glass9c526332018-07-06 10:27:28 -0600634elif options.test_coverage:
635 RunTestCoverage()