blob: cfe3e04c7ada4aea734e252bcadb44c06345b09c [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 Glassb5f0daf2019-05-17 22:00:41 -060022from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, 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 Glassf6b64812019-05-17 22:00:36 -060049 return prop, [tools.ToChar(x) for x in data]
Simon Glassf9b88b32018-07-06 10:27:29 -060050
51
Simon Glass2ba98752018-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 Glasse0e62752018-10-01 21:12:41 -060064 tools.FinaliseOutputDir()
Simon Glass2ba98752018-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 Glasse44bc832019-07-20 12:23:39 -060079
Simon Glass2ba98752018-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 Glass2a2d91d2018-07-06 10:27:28 -060083 self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
Simon Glass2ba98752018-07-06 10:27:24 -060084
Simon Glasse44bc832019-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 Glass2ba98752018-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 Glass2ab6e132019-05-17 22:00:39 -060092 with open(fname, 'rb') as fd:
Simon Glass2ba98752018-07-06 10:27:24 -060093 data = fd.read()
94 os.remove(fname)
95 with self.assertRaises(IOError):
Simon Glass2ab6e132019-05-17 22:00:39 -060096 open(fname, 'rb')
Simon Glass2ba98752018-07-06 10:27:24 -060097 self.dtb.Flush()
Simon Glass2ab6e132019-05-17 22:00:39 -060098 with open(fname, 'rb') as fd:
Simon Glass2ba98752018-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 Glass96066242018-07-06 10:27:27 -0600107 self.assertTrue(isinstance(self.dtb.GetContents(), bytearray))
Simon Glass2ba98752018-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 Glass2a2d91d2018-07-06 10:27:28 -0600114 'intarray', 'intval', 'longbytearray', 'notstring',
Simon Glass2ba98752018-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 Glass2a2d91d2018-07-06 10:27:28 -0600121 fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
Simon Glass2ba98752018-07-06 10:27:24 -0600122 self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
123
Simon Glass94a7c602018-07-17 13:25:46 -0600124 def testGetFdt(self):
125 node = self.dtb.GetNode('/spl-test')
126 self.assertEqual(self.dtb, node.GetFdt())
Simon Glass2ba98752018-07-06 10:27:24 -0600127
Simon Glassb5f0daf2019-05-17 22:00:41 -0600128 def testBytesToValue(self):
129 self.assertEqual(BytesToValue(b'this\0is\0'),
130 (TYPE_STRING, ['this', 'is']))
131
Simon Glass2ba98752018-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 Glasse0e62752018-10-01 21:12:41 -0600141 tools.FinaliseOutputDir()
Simon Glass2ba98752018-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 Glass2a2d91d2018-07-06 10:27:28 -0600161 with self.assertRaises(libfdt.FdtException):
162 self.node.DeleteProp('missing')
Simon Glass2ba98752018-07-06 10:27:24 -0600163
Simon Glassf9b88b32018-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 Glass2ba98752018-07-06 10:27:24 -0600170 def testFindNode(self):
Simon Glass1d858882018-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 Glass2ba98752018-07-06 10:27:24 -0600173 self.assertEqual('i2c@0', node.name)
Simon Glass1d858882018-07-17 13:25:41 -0600174 subnode = node.FindNode('pmic@9')
Simon Glass2ba98752018-07-06 10:27:24 -0600175 self.assertEqual('pmic@9', subnode.name)
Simon Glass1d858882018-07-17 13:25:41 -0600176 self.assertEqual(None, node.FindNode('missing'))
Simon Glass2ba98752018-07-06 10:27:24 -0600177
Simon Glassf9b88b32018-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 Glass94a7c602018-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 Glass2ba98752018-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 Glasse0e62752018-10-01 21:12:41 -0600222 tools.FinaliseOutputDir()
Simon Glass2ba98752018-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 Glassb9066ff2018-07-06 10:27:30 -0600229 def testMissingNode(self):
230 self.assertEqual(None, self.dtb.GetNode('missing'))
231
Simon Glass2a2d91d2018-07-06 10:27:28 -0600232 def testPhandle(self):
233 dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
Simon Glass760b7172018-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 Glass2a2d91d2018-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 Glass50c59522018-07-26 14:02:13 -0600246 p = self.fdt.getprop(self.node.Offset(), prop_name)
Simon Glass2a2d91d2018-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')
252 self.assertEqual(fdt.TYPE_BOOL, prop.type)
253 self.assertEqual(True, prop.value)
254
255 prop = self._ConvertProp('intval')
256 self.assertEqual(fdt.TYPE_INT, prop.type)
257 self.assertEqual(1, fdt32_to_cpu(prop.value))
258
259 prop = self._ConvertProp('intarray')
260 self.assertEqual(fdt.TYPE_INT, prop.type)
261 val = [fdt32_to_cpu(val) for val in prop.value]
262 self.assertEqual([2, 3, 4], val)
263
264 prop = self._ConvertProp('byteval')
265 self.assertEqual(fdt.TYPE_BYTE, prop.type)
266 self.assertEqual(5, ord(prop.value))
267
268 prop = self._ConvertProp('longbytearray')
269 self.assertEqual(fdt.TYPE_BYTE, prop.type)
270 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')
274 self.assertEqual(fdt.TYPE_STRING, prop.type)
275 self.assertEqual('message', prop.value)
276
277 prop = self._ConvertProp('stringarray')
278 self.assertEqual(fdt.TYPE_STRING, prop.type)
279 self.assertEqual(['multi-word', 'message'], prop.value)
280
281 prop = self._ConvertProp('notstring')
282 self.assertEqual(fdt.TYPE_BYTE, prop.type)
283 val = [ord(val) for val in prop.value]
284 self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
285
Simon Glass2ba98752018-07-06 10:27:24 -0600286 def testGetEmpty(self):
287 """Tests the GetEmpty() function for the various supported types"""
288 self.assertEqual(True, fdt.Prop.GetEmpty(fdt.TYPE_BOOL))
289 self.assertEqual(chr(0), fdt.Prop.GetEmpty(fdt.TYPE_BYTE))
Simon Glass194b8d52019-05-17 22:00:33 -0600290 self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(fdt.TYPE_INT))
Simon Glass2ba98752018-07-06 10:27:24 -0600291 self.assertEqual('', fdt.Prop.GetEmpty(fdt.TYPE_STRING))
292
293 def testGetOffset(self):
294 """Test we can get the offset of a property"""
Simon Glassf9b88b32018-07-06 10:27:29 -0600295 prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
296 self.assertEqual(prop.value, value)
Simon Glass2ba98752018-07-06 10:27:24 -0600297
298 def testWiden(self):
299 """Test widening of values"""
300 node2 = self.dtb.GetNode('/spl-test2')
Simon Glasse144caf2020-10-03 11:31:27 -0600301 node3 = self.dtb.GetNode('/spl-test3')
Simon Glass2ba98752018-07-06 10:27:24 -0600302 prop = self.node.props['intval']
303
304 # No action
305 prop2 = node2.props['intval']
306 prop.Widen(prop2)
307 self.assertEqual(fdt.TYPE_INT, prop.type)
308 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)
313 self.assertEqual(fdt.TYPE_INT, prop.type)
314 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 Glasse144caf2020-10-03 11:31:27 -0600320 prop3 = node3.props['longbytearray']
Simon Glass2ba98752018-07-06 10:27:24 -0600321 self.assertFalse(isinstance(prop2.value, list))
322 self.assertEqual(4, len(prop2.value))
Simon Glasse144caf2020-10-03 11:31:27 -0600323 self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
Simon Glass2ba98752018-07-06 10:27:24 -0600324 prop2.Widen(prop)
325 self.assertTrue(isinstance(prop2.value, list))
326 self.assertEqual(9, len(prop2.value))
Simon Glasse144caf2020-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 Glass2ba98752018-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 Glass116adec2018-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 Glassfa80c252018-09-14 04:57:13 -0600360 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-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 Glassfa80c252018-09-14 04:57:13 -0600368 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600369
370 # This should fail since it would need to increase the device-tree size
Simon Glassfa80c252018-09-14 04:57:13 -0600371 self.node.AddZeroProp('four')
Simon Glass116adec2018-07-06 10:27:38 -0600372 with self.assertRaises(libfdt.FdtException) as e:
Simon Glassfa80c252018-09-14 04:57:13 -0600373 self.dtb.Sync(auto_resize=False)
Simon Glass116adec2018-07-06 10:27:38 -0600374 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
Simon Glass64349612018-09-14 04:57:16 -0600375 self.dtb.Sync(auto_resize=True)
Simon Glass116adec2018-07-06 10:27:38 -0600376
Simon Glassfa80c252018-09-14 04:57:13 -0600377 def testAddNode(self):
378 self.fdt.pack()
Simon Glasse21c27a2018-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 Glassfa80c252018-09-14 04:57:13 -0600387
Simon Glass64349612018-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
400 val = '123' + chr(0) + '456'
401 self.node.AddString('string', val)
402 self.dtb.Sync(auto_resize=True)
403 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600404 self.assertEqual(tools.ToBytes(val) + b'\0', data)
Simon Glass64349612018-09-14 04:57:16 -0600405
406 self.fdt.pack()
407 self.node.SetString('string', val + 'x')
408 with self.assertRaises(libfdt.FdtException) as e:
409 self.dtb.Sync(auto_resize=False)
410 self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
411 self.node.SetString('string', val[:-1])
412
413 prop = self.node.props['string']
Simon Glassf6b64812019-05-17 22:00:36 -0600414 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600415 self.dtb.Sync(auto_resize=False)
416 data = self.fdt.getprop(self.node.Offset(), 'string')
Simon Glassf6b64812019-05-17 22:00:36 -0600417 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600418
419 self.node.AddEmptyProp('empty', 5)
420 self.dtb.Sync(auto_resize=True)
421 prop = self.node.props['empty']
Simon Glassf6b64812019-05-17 22:00:36 -0600422 prop.SetData(tools.ToBytes(val))
Simon Glass64349612018-09-14 04:57:16 -0600423 self.dtb.Sync(auto_resize=False)
424 data = self.fdt.getprop(self.node.Offset(), 'empty')
Simon Glassf6b64812019-05-17 22:00:36 -0600425 self.assertEqual(tools.ToBytes(val), data)
Simon Glass64349612018-09-14 04:57:16 -0600426
Simon Glassf6b64812019-05-17 22:00:36 -0600427 self.node.SetData('empty', b'123')
428 self.assertEqual(b'123', prop.bytes)
Simon Glass64349612018-09-14 04:57:16 -0600429
Simon Glassc0639172020-07-09 18:39:44 -0600430 # Trying adding a lot of data at once
431 self.node.AddData('data', tools.GetBytes(65, 20000))
432 self.dtb.Sync(auto_resize=True)
433
Simon Glass746aee32018-09-14 04:57:17 -0600434 def testFromData(self):
435 dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
436 self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
437
438 self.node.AddEmptyProp('empty', 5)
439 self.dtb.Sync(auto_resize=True)
440 self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
441
Simon Glassd9dad102019-07-20 12:23:37 -0600442 def testMissingSetInt(self):
443 """Test handling of a missing property with SetInt"""
444 with self.assertRaises(ValueError) as e:
445 self.node.SetInt('one', 1)
446 self.assertIn("node '/spl-test': Missing property 'one'",
447 str(e.exception))
448
449 def testMissingSetData(self):
450 """Test handling of a missing property with SetData"""
451 with self.assertRaises(ValueError) as e:
452 self.node.SetData('one', b'data')
453 self.assertIn("node '/spl-test': Missing property 'one'",
454 str(e.exception))
455
456 def testMissingSetString(self):
457 """Test handling of a missing property with SetString"""
458 with self.assertRaises(ValueError) as e:
459 self.node.SetString('one', 1)
460 self.assertIn("node '/spl-test': Missing property 'one'",
461 str(e.exception))
462
Simon Glassf6e02492019-07-20 12:24:08 -0600463 def testGetFilename(self):
464 """Test the dtb filename can be provided"""
465 self.assertEqual(tools.GetOutputFilename('source.dtb'),
466 self.dtb.GetFilename())
467
Simon Glass2ba98752018-07-06 10:27:24 -0600468
Simon Glass2a2d91d2018-07-06 10:27:28 -0600469class TestFdtUtil(unittest.TestCase):
470 """Tests for the fdt_util module
471
472 This module will likely be mostly replaced at some point, once upstream
473 libfdt has better Python support. For now, this provides tests for current
474 functionality.
475 """
476 @classmethod
477 def setUpClass(cls):
478 tools.PrepareOutputDir(None)
479
Simon Glasse0e62752018-10-01 21:12:41 -0600480 @classmethod
481 def tearDownClass(cls):
482 tools.FinaliseOutputDir()
483
Simon Glass2a2d91d2018-07-06 10:27:28 -0600484 def setUp(self):
485 self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
486 self.node = self.dtb.GetNode('/spl-test')
487
488 def testGetInt(self):
489 self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
490 self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
491
492 with self.assertRaises(ValueError) as e:
493 self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
494 self.assertIn("property 'intarray' has list value: expecting a single "
495 'integer', str(e.exception))
496
497 def testGetString(self):
498 self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
499 self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
500 'test'))
501
502 with self.assertRaises(ValueError) as e:
503 self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
504 self.assertIn("property 'stringarray' has list value: expecting a "
505 'single string', str(e.exception))
506
507 def testGetBool(self):
508 self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
509 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
510 self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
511 self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
512
Simon Glass3af8e492018-07-17 13:25:40 -0600513 def testGetByte(self):
514 self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
515 self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
516
517 with self.assertRaises(ValueError) as e:
518 fdt_util.GetByte(self.node, 'longbytearray')
519 self.assertIn("property 'longbytearray' has list value: expecting a "
520 'single byte', str(e.exception))
521
522 with self.assertRaises(ValueError) as e:
523 fdt_util.GetByte(self.node, 'intval')
524 self.assertIn("property 'intval' has length 4, expecting 1",
525 str(e.exception))
526
Simon Glass94a7c602018-07-17 13:25:46 -0600527 def testGetPhandleList(self):
528 dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
529 node = dtb.GetNode('/phandle-source2')
530 self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
531 node = dtb.GetNode('/phandle-source')
532 self.assertEqual([1, 2, 11, 3, 12, 13, 1],
533 fdt_util.GetPhandleList(node, 'clocks'))
534 self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
535
Simon Glass53af22a2018-07-17 13:25:32 -0600536 def testGetDataType(self):
537 self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
538 self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
539 str))
540 with self.assertRaises(ValueError) as e:
541 self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
542 bool))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600543 def testFdtCellsToCpu(self):
544 val = self.node.props['intarray'].value
545 self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
546 self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
547
548 dtb2 = fdt.FdtScan('tools/dtoc/dtoc_test_addr64.dts')
Simon Glasse66d3182019-05-17 22:00:40 -0600549 node1 = dtb2.GetNode('/test1')
550 val = node1.props['reg'].value
Simon Glass2a2d91d2018-07-06 10:27:28 -0600551 self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
552
Simon Glasse66d3182019-05-17 22:00:40 -0600553 node2 = dtb2.GetNode('/test2')
554 val = node2.props['reg'].value
555 self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
556 self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
557 2))
558 self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
559
Simon Glass2a2d91d2018-07-06 10:27:28 -0600560 def testEnsureCompiled(self):
Simon Glassa004f292019-07-20 12:23:49 -0600561 """Test a degenerate case of this function (file already compiled)"""
Simon Glass2a2d91d2018-07-06 10:27:28 -0600562 dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
563 self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
564
Simon Glassa004f292019-07-20 12:23:49 -0600565 def testEnsureCompiledTmpdir(self):
566 """Test providing a temporary directory"""
567 try:
568 old_outdir = tools.outdir
569 tools.outdir= None
570 tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
571 dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts',
572 tmpdir)
573 self.assertEqual(tmpdir, os.path.dirname(dtb))
574 shutil.rmtree(tmpdir)
575 finally:
576 tools.outdir= old_outdir
577
Simon Glass2a2d91d2018-07-06 10:27:28 -0600578
579def RunTestCoverage():
580 """Run the tests and check that we get 100% coverage"""
581 test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
582 ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
583
584
Simon Glass2ba98752018-07-06 10:27:24 -0600585def RunTests(args):
586 """Run all the test we have for the fdt model
587
588 Args:
589 args: List of positional args provided to fdt. This can hold a test
590 name to execute (as in 'fdt -t testFdt', for example)
591 """
592 result = unittest.TestResult()
593 sys.argv = [sys.argv[0]]
594 test_name = args and args[0] or None
Simon Glass2a2d91d2018-07-06 10:27:28 -0600595 for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
Simon Glass2ba98752018-07-06 10:27:24 -0600596 if test_name:
597 try:
598 suite = unittest.TestLoader().loadTestsFromName(test_name, module)
599 except AttributeError:
600 continue
601 else:
602 suite = unittest.TestLoader().loadTestsFromTestCase(module)
603 suite.run(result)
604
Simon Glass90a81322019-05-17 22:00:31 -0600605 print(result)
Simon Glass2ba98752018-07-06 10:27:24 -0600606 for _, err in result.errors:
Simon Glass90a81322019-05-17 22:00:31 -0600607 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600608 for _, err in result.failures:
Simon Glass90a81322019-05-17 22:00:31 -0600609 print(err)
Simon Glass2ba98752018-07-06 10:27:24 -0600610
611if __name__ != '__main__':
612 sys.exit(1)
613
614parser = OptionParser()
Simon Glass2a2d91d2018-07-06 10:27:28 -0600615parser.add_option('-B', '--build-dir', type='string', default='b',
616 help='Directory containing the build output')
Simon Glass11ae93e2018-10-01 21:12:47 -0600617parser.add_option('-P', '--processes', type=int,
618 help='set number of processes to use for running tests')
Simon Glass2ba98752018-07-06 10:27:24 -0600619parser.add_option('-t', '--test', action='store_true', dest='test',
620 default=False, help='run tests')
Simon Glass2a2d91d2018-07-06 10:27:28 -0600621parser.add_option('-T', '--test-coverage', action='store_true',
622 default=False, help='run tests and check for 100% coverage')
Simon Glass2ba98752018-07-06 10:27:24 -0600623(options, args) = parser.parse_args()
624
625# Run our meagre tests
626if options.test:
627 RunTests(args)
Simon Glass2a2d91d2018-07-06 10:27:28 -0600628elif options.test_coverage:
629 RunTestCoverage()