]> Git Repo - u-boot.git/blob - tools/dtoc/test_fdt.py
32fa69cbb01855ea8d1144676956b3f94ea7200c
[u-boot.git] / tools / dtoc / test_fdt.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0+
3
4 """
5 Tests for the Fdt module
6 Copyright (c) 2018 Google, Inc
7 Written by Simon Glass <[email protected]>
8 """
9
10 from argparse import ArgumentParser
11 import os
12 import shutil
13 import sys
14 import tempfile
15 import unittest
16
17 # Bring in the patman libraries
18 our_path = os.path.dirname(os.path.realpath(__file__))
19 sys.path.insert(1, os.path.join(our_path, '..'))
20
21 # Bring in the libfdt module
22 sys.path.insert(2, 'scripts/dtc/pylibfdt')
23 sys.path.insert(2, os.path.join(our_path, '../../scripts/dtc/pylibfdt'))
24 sys.path.insert(2, os.path.join(our_path,
25                 '../../build-sandbox_spl/scripts/dtc/pylibfdt'))
26
27 #pylint: disable=wrong-import-position
28 from dtoc import fdt
29 from dtoc import fdt_util
30 from dtoc.fdt_util import fdt32_to_cpu, fdt64_to_cpu
31 from dtoc.fdt import Type, BytesToValue
32 import libfdt
33 from u_boot_pylib import test_util
34 from u_boot_pylib import tools
35
36 #pylint: disable=protected-access
37
38 def _get_property_value(dtb, node, prop_name):
39     """Low-level function to get the property value based on its offset
40
41     This looks directly in the device tree at the property's offset to find
42     its value. It is useful as a check that the property is in the correct
43     place.
44
45     Args:
46         node: Node to look in
47         prop_name: Property name to find
48
49     Returns:
50         Tuple:
51             Prop object found
52             Value of property as a string (found using property offset)
53     """
54     prop = node.props[prop_name]
55
56     # Add 12, which is sizeof(struct fdt_property), to get to start of data
57     offset = prop.GetOffset() + 12
58     data = dtb.GetContents()[offset:offset + len(prop.value)]
59     return prop, [chr(x) for x in data]
60
61 def find_dtb_file(dts_fname):
62     """Locate a test file in the test/ directory
63
64     Args:
65         dts_fname (str): Filename to find, e.g. 'dtoc_test_simple.dts]
66
67     Returns:
68         str: Path to the test filename
69     """
70     return os.path.join('tools/dtoc/test', dts_fname)
71
72
73 class TestFdt(unittest.TestCase):
74     """Tests for the Fdt module
75
76     This includes unit tests for some functions and functional tests for the fdt
77     module.
78     """
79     @classmethod
80     def setUpClass(cls):
81         tools.prepare_output_dir(None)
82
83     @classmethod
84     def tearDownClass(cls):
85         tools.finalise_output_dir()
86
87     def setUp(self):
88         self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
89
90     def test_fdt(self):
91         """Test that we can open an Fdt"""
92         self.dtb.Scan()
93         root = self.dtb.GetRoot()
94         self.assertTrue(isinstance(root, fdt.Node))
95
96     def test_get_node(self):
97         """Test the GetNode() method"""
98         node = self.dtb.GetNode('/spl-test')
99         self.assertTrue(isinstance(node, fdt.Node))
100
101         node = self.dtb.GetNode('/i2c@0/pmic@9')
102         self.assertTrue(isinstance(node, fdt.Node))
103         self.assertEqual('pmic@9', node.name)
104         self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
105
106         node = self.dtb.GetNode('/')
107         self.assertTrue(isinstance(node, fdt.Node))
108         self.assertEqual(0, node.Offset())
109
110     def test_flush(self):
111         """Check that we can flush the device tree out to its file"""
112         fname = self.dtb._fname
113         with open(fname, 'rb') as inf:
114             inf.read()
115         os.remove(fname)
116         with self.assertRaises(IOError):
117             with open(fname, 'rb'):
118                 pass
119         self.dtb.Flush()
120         with open(fname, 'rb') as inf:
121             inf.read()
122
123     def test_pack(self):
124         """Test that packing a device tree works"""
125         self.dtb.Pack()
126
127     def test_get_fdt_raw(self):
128         """Tetst that we can access the raw device-tree data"""
129         self.assertTrue(isinstance(self.dtb.GetContents(), bytes))
130
131     def test_get_props(self):
132         """Tests obtaining a list of properties"""
133         node = self.dtb.GetNode('/spl-test')
134         props = self.dtb.GetProps(node)
135         self.assertEqual(['boolval', 'bootph-all', 'bytearray', 'byteval',
136                           'compatible', 'int64val', 'intarray', 'intval',
137                           'longbytearray', 'maybe-empty-int', 'notstring',
138                           'stringarray', 'stringval', ],
139                          sorted(props.keys()))
140
141     def test_check_error(self):
142         """Tests the ChecKError() function"""
143         with self.assertRaises(ValueError) as exc:
144             fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
145         self.assertIn('FDT_ERR_NOTFOUND: hello', str(exc.exception))
146
147     def test_get_fdt(self):
148         """Test getting an Fdt object from a node"""
149         node = self.dtb.GetNode('/spl-test')
150         self.assertEqual(self.dtb, node.GetFdt())
151
152     def test_bytes_to_value(self):
153         """Test converting a string list into Python"""
154         self.assertEqual(BytesToValue(b'this\0is\0'),
155                          (Type.STRING, ['this', 'is']))
156
157 class TestNode(unittest.TestCase):
158     """Test operation of the Node class"""
159
160     @classmethod
161     def setUpClass(cls):
162         tools.prepare_output_dir(None)
163
164     @classmethod
165     def tearDownClass(cls):
166         tools.finalise_output_dir()
167
168     def setUp(self):
169         self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
170         self.node = self.dtb.GetNode('/spl-test')
171         self.fdt = self.dtb.GetFdtObj()
172
173     def test_offset(self):
174         """Tests that we can obtain the offset of a node"""
175         self.assertTrue(self.node.Offset() > 0)
176
177     def test_delete(self):
178         """Tests that we can delete a property"""
179         node2 = self.dtb.GetNode('/spl-test2')
180         offset1 = node2.Offset()
181         self.node.DeleteProp('intval')
182         offset2 = node2.Offset()
183         self.assertTrue(offset2 < offset1)
184         self.node.DeleteProp('intarray')
185         offset3 = node2.Offset()
186         self.assertTrue(offset3 < offset2)
187         with self.assertRaises(libfdt.FdtException):
188             self.node.DeleteProp('missing')
189
190     def test_delete_get_offset(self):
191         """Test that property offset update when properties are deleted"""
192         self.node.DeleteProp('intval')
193         prop, value = _get_property_value(self.dtb, self.node, 'longbytearray')
194         self.assertEqual(prop.value, value)
195
196     def test_find_node(self):
197         """Tests that we can find a node using the FindNode() functoin"""
198         node = self.dtb.GetRoot().FindNode('i2c@0')
199         self.assertEqual('i2c@0', node.name)
200         subnode = node.FindNode('pmic@9')
201         self.assertEqual('pmic@9', subnode.name)
202         self.assertEqual(None, node.FindNode('missing'))
203
204     def test_refresh_missing_node(self):
205         """Test refreshing offsets when an extra node is present in dtb"""
206         # Delete it from our tables, not the device tree
207         del self.dtb._root.subnodes[-1]
208         with self.assertRaises(ValueError) as exc:
209             self.dtb.Refresh()
210         self.assertIn('Internal error, offset', str(exc.exception))
211
212     def test_refresh_extra_node(self):
213         """Test refreshing offsets when an expected node is missing"""
214         # Delete it from the device tre, not our tables
215         self.fdt.del_node(self.node.Offset())
216         with self.assertRaises(ValueError) as exc:
217             self.dtb.Refresh()
218         self.assertIn('Internal error, node name mismatch '
219                       'spl-test != spl-test2', str(exc.exception))
220
221     def test_refresh_missing_prop(self):
222         """Test refreshing offsets when an extra property is present in dtb"""
223         # Delete it from our tables, not the device tree
224         del self.node.props['notstring']
225         with self.assertRaises(ValueError) as exc:
226             self.dtb.Refresh()
227         self.assertIn("Internal error, node '/spl-test' property 'notstring' missing, offset ",
228                       str(exc.exception))
229
230     def test_lookup_phandle(self):
231         """Test looking up a single phandle"""
232         dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
233         node = dtb.GetNode('/phandle-source2')
234         prop = node.props['clocks']
235         target = dtb.GetNode('/phandle-target')
236         self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
237
238     def test_add_node_space(self):
239         """Test adding a single node when out of space"""
240         self.fdt.pack()
241         self.node.AddSubnode('subnode')
242         with self.assertRaises(libfdt.FdtException) as exc:
243             self.dtb.Sync(auto_resize=False)
244         self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
245
246         self.dtb.Sync(auto_resize=True)
247         offset = self.fdt.path_offset('/spl-test/subnode')
248         self.assertTrue(offset > 0)
249
250     def test_add_nodes(self):
251         """Test adding various subnode and properies"""
252         node = self.dtb.GetNode('/i2c@0')
253
254         # Add one more node next to the pmic one
255         sn1 = node.AddSubnode('node-one')
256         sn1.AddInt('integer-a', 12)
257         sn1.AddInt('integer-b', 23)
258
259         # Sync so that everything is clean
260         self.dtb.Sync(auto_resize=True)
261
262         # Add two subnodes next to pmic and node-one
263         sn2 = node.AddSubnode('node-two')
264         sn2.AddInt('integer-2a', 34)
265         sn2.AddInt('integer-2b', 45)
266
267         sn3 = node.AddSubnode('node-three')
268         sn3.AddInt('integer-3', 123)
269
270         # Add a property to the node after i2c@0 to check that this is not
271         # disturbed by adding a subnode to i2c@0
272         orig_node = self.dtb.GetNode('/orig-node')
273         orig_node.AddInt('integer-4', 456)
274
275         # Add a property to the pmic node to check that pmic properties are not
276         # disturbed
277         pmic = self.dtb.GetNode('/i2c@0/pmic@9')
278         pmic.AddInt('integer-5', 567)
279
280         self.dtb.Sync(auto_resize=True)
281
282     def test_add_one_node(self):
283         """Testing deleting and adding a subnode before syncing"""
284         subnode = self.node.AddSubnode('subnode')
285         self.node.AddSubnode('subnode2')
286         self.dtb.Sync(auto_resize=True)
287
288         # Delete a node and add a new one
289         subnode.Delete()
290         self.node.AddSubnode('subnode3')
291         self.dtb.Sync()
292
293     def test_refresh_name_mismatch(self):
294         """Test name mismatch when syncing nodes and properties"""
295         self.node.AddInt('integer-a', 12)
296
297         wrong_offset = self.dtb.GetNode('/i2c@0')._offset
298         self.node._offset = wrong_offset
299         with self.assertRaises(ValueError) as exc:
300             self.dtb.Sync()
301         self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
302                       str(exc.exception))
303
304         with self.assertRaises(ValueError) as exc:
305             self.node.Refresh(wrong_offset)
306         self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
307                       str(exc.exception))
308
309
310 class TestProp(unittest.TestCase):
311     """Test operation of the Prop class"""
312
313     @classmethod
314     def setUpClass(cls):
315         tools.prepare_output_dir(None)
316
317     @classmethod
318     def tearDownClass(cls):
319         tools.finalise_output_dir()
320
321     def setUp(self):
322         self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
323         self.node = self.dtb.GetNode('/spl-test')
324         self.fdt = self.dtb.GetFdtObj()
325
326     def test_missing_node(self):
327         """Test GetNode() when the node is missing"""
328         self.assertEqual(None, self.dtb.GetNode('missing'))
329
330     def test_phandle(self):
331         """Test GetNode() on a phandle"""
332         dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
333         node = dtb.GetNode('/phandle-source2')
334         prop = node.props['clocks']
335         self.assertTrue(fdt32_to_cpu(prop.value) > 0)
336
337     def _convert_prop(self, prop_name):
338         """Helper function to look up a property in self.node and return it
339
340         Args:
341             str: Property name to find
342
343         Returns:
344             fdt.Prop: object for this property
345         """
346         prop = self.fdt.getprop(self.node.Offset(), prop_name)
347         return fdt.Prop(self.node, -1, prop_name, prop)
348
349     def test_make_prop(self):
350         """Test we can convert all the the types that are supported"""
351         prop = self._convert_prop('boolval')
352         self.assertEqual(Type.BOOL, prop.type)
353         self.assertEqual(True, prop.value)
354
355         prop = self._convert_prop('intval')
356         self.assertEqual(Type.INT, prop.type)
357         self.assertEqual(1, fdt32_to_cpu(prop.value))
358
359         prop = self._convert_prop('int64val')
360         self.assertEqual(Type.INT, prop.type)
361         self.assertEqual(0x123456789abcdef0, fdt64_to_cpu(prop.value))
362
363         prop = self._convert_prop('intarray')
364         self.assertEqual(Type.INT, prop.type)
365         val = [fdt32_to_cpu(val) for val in prop.value]
366         self.assertEqual([2, 3, 4], val)
367
368         prop = self._convert_prop('byteval')
369         self.assertEqual(Type.BYTE, prop.type)
370         self.assertEqual(5, ord(prop.value))
371
372         prop = self._convert_prop('longbytearray')
373         self.assertEqual(Type.BYTE, prop.type)
374         val = [ord(val) for val in prop.value]
375         self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
376
377         prop = self._convert_prop('stringval')
378         self.assertEqual(Type.STRING, prop.type)
379         self.assertEqual('message', prop.value)
380
381         prop = self._convert_prop('stringarray')
382         self.assertEqual(Type.STRING, prop.type)
383         self.assertEqual(['multi-word', 'message'], prop.value)
384
385         prop = self._convert_prop('notstring')
386         self.assertEqual(Type.BYTE, prop.type)
387         val = [ord(val) for val in prop.value]
388         self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
389
390     def test_get_empty(self):
391         """Tests the GetEmpty() function for the various supported types"""
392         self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
393         self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
394         self.assertEqual(tools.get_bytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
395         self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
396
397     def test_get_offset(self):
398         """Test we can get the offset of a property"""
399         prop, value = _get_property_value(self.dtb, self.node, 'longbytearray')
400         self.assertEqual(prop.value, value)
401
402     def test_widen(self):
403         """Test widening of values"""
404         node2 = self.dtb.GetNode('/spl-test2')
405         node3 = self.dtb.GetNode('/spl-test3')
406         prop = self.node.props['intval']
407
408         # No action
409         prop2 = node2.props['intval']
410         prop.Widen(prop2)
411         self.assertEqual(Type.INT, prop.type)
412         self.assertEqual(1, fdt32_to_cpu(prop.value))
413
414         # Convert single value to array
415         prop2 = self.node.props['intarray']
416         prop.Widen(prop2)
417         self.assertEqual(Type.INT, prop.type)
418         self.assertTrue(isinstance(prop.value, list))
419
420         # A 4-byte array looks like a single integer. When widened by a longer
421         # byte array, it should turn into an array.
422         prop = self.node.props['longbytearray']
423         prop2 = node2.props['longbytearray']
424         prop3 = node3.props['longbytearray']
425         self.assertFalse(isinstance(prop2.value, list))
426         self.assertEqual(4, len(prop2.value))
427         self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
428         prop2.Widen(prop)
429         self.assertTrue(isinstance(prop2.value, list))
430         self.assertEqual(9, len(prop2.value))
431         self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
432                           '\0', '\0', '\0', '\0'], prop2.value)
433         prop3.Widen(prop)
434         self.assertTrue(isinstance(prop3.value, list))
435         self.assertEqual(9, len(prop3.value))
436         self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
437                           '\x0e', '\x0f', '\x10', '\0'], prop3.value)
438
439     def test_widen_more(self):
440         """More tests of widening values"""
441         node2 = self.dtb.GetNode('/spl-test2')
442         node3 = self.dtb.GetNode('/spl-test3')
443         prop = self.node.props['intval']
444
445         # Test widening a single string into a string array
446         prop = self.node.props['stringval']
447         prop2 = node2.props['stringarray']
448         self.assertFalse(isinstance(prop.value, list))
449         self.assertEqual(7, len(prop.value))
450         prop.Widen(prop2)
451         self.assertTrue(isinstance(prop.value, list))
452         self.assertEqual(3, len(prop.value))
453
454         # Enlarging an existing array
455         prop = self.node.props['stringarray']
456         prop2 = node2.props['stringarray']
457         self.assertTrue(isinstance(prop.value, list))
458         self.assertEqual(2, len(prop.value))
459         prop.Widen(prop2)
460         self.assertTrue(isinstance(prop.value, list))
461         self.assertEqual(3, len(prop.value))
462
463         # Widen an array of ints with an int (should do nothing)
464         prop = self.node.props['intarray']
465         prop2 = node2.props['intval']
466         self.assertEqual(Type.INT, prop.type)
467         self.assertEqual(3, len(prop.value))
468         prop.Widen(prop2)
469         self.assertEqual(Type.INT, prop.type)
470         self.assertEqual(3, len(prop.value))
471
472         # Widen an empty bool to an int
473         prop = self.node.props['maybe-empty-int']
474         prop3 = node3.props['maybe-empty-int']
475         self.assertEqual(Type.BOOL, prop.type)
476         self.assertEqual(True, prop.value)
477         self.assertEqual(Type.INT, prop3.type)
478         self.assertFalse(isinstance(prop.value, list))
479         self.assertEqual(4, len(prop3.value))
480         prop.Widen(prop3)
481         self.assertEqual(Type.INT, prop.type)
482         self.assertTrue(isinstance(prop.value, list))
483         self.assertEqual(1, len(prop.value))
484
485     def test_add(self):
486         """Test adding properties"""
487         self.fdt.pack()
488         # This function should automatically expand the device tree
489         self.node.AddZeroProp('one')
490         self.node.AddZeroProp('two')
491         self.node.AddZeroProp('three')
492         self.dtb.Sync(auto_resize=True)
493
494         # Updating existing properties should be OK, since the device-tree size
495         # does not change
496         self.fdt.pack()
497         self.node.SetInt('one', 1)
498         self.node.SetInt('two', 2)
499         self.node.SetInt('three', 3)
500         self.dtb.Sync(auto_resize=False)
501
502         # This should fail since it would need to increase the device-tree size
503         self.node.AddZeroProp('four')
504         with self.assertRaises(libfdt.FdtException) as exc:
505             self.dtb.Sync(auto_resize=False)
506         self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
507         self.dtb.Sync(auto_resize=True)
508
509     def test_add_more(self):
510         """Test various other methods for adding and setting properties"""
511         self.node.AddZeroProp('one')
512         self.dtb.Sync(auto_resize=True)
513         data = self.fdt.getprop(self.node.Offset(), 'one')
514         self.assertEqual(0, fdt32_to_cpu(data))
515
516         self.node.SetInt('one', 1)
517         self.dtb.Sync(auto_resize=False)
518         data = self.fdt.getprop(self.node.Offset(), 'one')
519         self.assertEqual(1, fdt32_to_cpu(data))
520
521         val = 1234
522         self.node.AddInt('integer', val)
523         self.dtb.Sync(auto_resize=True)
524         data = self.fdt.getprop(self.node.Offset(), 'integer')
525         self.assertEqual(val, fdt32_to_cpu(data))
526
527         val = '123' + chr(0) + '456'
528         self.node.AddString('string', val)
529         self.dtb.Sync(auto_resize=True)
530         data = self.fdt.getprop(self.node.Offset(), 'string')
531         self.assertEqual(tools.to_bytes(val) + b'\0', data)
532
533         self.fdt.pack()
534         self.node.SetString('string', val + 'x')
535         with self.assertRaises(libfdt.FdtException) as exc:
536             self.dtb.Sync(auto_resize=False)
537         self.assertIn('FDT_ERR_NOSPACE', str(exc.exception))
538         self.node.SetString('string', val[:-1])
539
540         prop = self.node.props['string']
541         prop.SetData(tools.to_bytes(val))
542         self.dtb.Sync(auto_resize=False)
543         data = self.fdt.getprop(self.node.Offset(), 'string')
544         self.assertEqual(tools.to_bytes(val), data)
545
546         self.node.AddEmptyProp('empty', 5)
547         self.dtb.Sync(auto_resize=True)
548         prop = self.node.props['empty']
549         prop.SetData(tools.to_bytes(val))
550         self.dtb.Sync(auto_resize=False)
551         data = self.fdt.getprop(self.node.Offset(), 'empty')
552         self.assertEqual(tools.to_bytes(val), data)
553
554         self.node.SetData('empty', b'123')
555         self.assertEqual(b'123', prop.bytes)
556
557         # Trying adding a lot of data at once
558         self.node.AddData('data', tools.get_bytes(65, 20000))
559         self.dtb.Sync(auto_resize=True)
560
561     def test_string_list(self):
562         """Test adding string-list property to a node"""
563         val = ['123', '456']
564         self.node.AddStringList('stringlist', val)
565         self.dtb.Sync(auto_resize=True)
566         data = self.fdt.getprop(self.node.Offset(), 'stringlist')
567         self.assertEqual(b'123\x00456\0', data)
568
569         val = []
570         self.node.AddStringList('stringlist', val)
571         self.dtb.Sync(auto_resize=True)
572         data = self.fdt.getprop(self.node.Offset(), 'stringlist')
573         self.assertEqual(b'', data)
574
575     def test_delete_node(self):
576         """Test deleting a node"""
577         old_offset = self.fdt.path_offset('/spl-test')
578         self.assertGreater(old_offset, 0)
579         self.node.Delete()
580         self.dtb.Sync()
581         new_offset = self.fdt.path_offset('/spl-test', libfdt.QUIET_NOTFOUND)
582         self.assertEqual(-libfdt.NOTFOUND, new_offset)
583
584     def test_from_data(self):
585         """Test creating an FDT from data"""
586         dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
587         self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
588
589         self.node.AddEmptyProp('empty', 5)
590         self.dtb.Sync(auto_resize=True)
591         self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
592
593     def test_missing_set_int(self):
594         """Test handling of a missing property with SetInt"""
595         with self.assertRaises(ValueError) as exc:
596             self.node.SetInt('one', 1)
597         self.assertIn("node '/spl-test': Missing property 'one'",
598                       str(exc.exception))
599
600     def test_missing_set_data(self):
601         """Test handling of a missing property with SetData"""
602         with self.assertRaises(ValueError) as exc:
603             self.node.SetData('one', b'data')
604         self.assertIn("node '/spl-test': Missing property 'one'",
605                       str(exc.exception))
606
607     def test_missing_set_string(self):
608         """Test handling of a missing property with SetString"""
609         with self.assertRaises(ValueError) as exc:
610             self.node.SetString('one', 1)
611         self.assertIn("node '/spl-test': Missing property 'one'",
612                       str(exc.exception))
613
614     def test_get_filename(self):
615         """Test the dtb filename can be provided"""
616         self.assertEqual(tools.get_output_filename('source.dtb'),
617                          self.dtb.GetFilename())
618
619
620 class TestFdtUtil(unittest.TestCase):
621     """Tests for the fdt_util module
622
623     This module will likely be mostly replaced at some point, once upstream
624     libfdt has better Python support. For now, this provides tests for current
625     functionality.
626     """
627     @classmethod
628     def setUpClass(cls):
629         tools.prepare_output_dir(None)
630
631     @classmethod
632     def tearDownClass(cls):
633         tools.finalise_output_dir()
634
635     def setUp(self):
636         self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
637         self.node = self.dtb.GetNode('/spl-test')
638
639     def test_get_int(self):
640         """Test getting an int from a node"""
641         self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
642         self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
643
644         with self.assertRaises(ValueError) as exc:
645             fdt_util.GetInt(self.node, 'intarray')
646         self.assertIn("property 'intarray' has list value: expecting a single "
647                       'integer', str(exc.exception))
648
649     def test_get_int64(self):
650         """Test getting a 64-bit int from a node"""
651         self.assertEqual(0x123456789abcdef0,
652                          fdt_util.GetInt64(self.node, 'int64val'))
653         self.assertEqual(3, fdt_util.GetInt64(self.node, 'missing', 3))
654
655         with self.assertRaises(ValueError) as exc:
656             fdt_util.GetInt64(self.node, 'intarray')
657         self.assertIn(
658             "property 'intarray' should be a list with 2 items for 64-bit values",
659             str(exc.exception))
660
661     def test_get_string(self):
662         """Test getting a string from a node"""
663         self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
664         self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
665                                                     'test'))
666         self.assertEqual('', fdt_util.GetString(self.node, 'boolval'))
667
668         with self.assertRaises(ValueError) as exc:
669             self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
670         self.assertIn("property 'stringarray' has list value: expecting a "
671                       'single string', str(exc.exception))
672
673     def test_get_string_list(self):
674         """Test getting a string list from a node"""
675         self.assertEqual(['message'],
676                          fdt_util.GetStringList(self.node, 'stringval'))
677         self.assertEqual(
678             ['multi-word', 'message'],
679             fdt_util.GetStringList(self.node, 'stringarray'))
680         self.assertEqual(['test'],
681                          fdt_util.GetStringList(self.node, 'missing', ['test']))
682         self.assertEqual([], fdt_util.GetStringList(self.node, 'boolval'))
683
684     def test_get_args(self):
685         """Test getting arguments from a node"""
686         node = self.dtb.GetNode('/orig-node')
687         self.assertEqual(['message'], fdt_util.GetArgs(self.node, 'stringval'))
688         self.assertEqual(
689             ['multi-word', 'message'],
690             fdt_util.GetArgs(self.node, 'stringarray'))
691         self.assertEqual([], fdt_util.GetArgs(self.node, 'boolval'))
692         self.assertEqual(['-n first', 'second', '-p', '123,456', '-x'],
693                          fdt_util.GetArgs(node, 'args'))
694         self.assertEqual(['a space', 'there'],
695                          fdt_util.GetArgs(node, 'args2'))
696         self.assertEqual(['-n', 'first', 'second', '-p', '123,456', '-x'],
697                          fdt_util.GetArgs(node, 'args3'))
698         with self.assertRaises(ValueError) as exc:
699             fdt_util.GetArgs(self.node, 'missing')
700         self.assertIn(
701             "Node '/spl-test': Expected property 'missing'",
702             str(exc.exception))
703
704     def test_get_bool(self):
705         """Test getting a bool from a node"""
706         self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
707         self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
708         self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
709         self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
710
711     def test_get_byte(self):
712         """Test getting a byte from a node"""
713         self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
714         self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
715
716         with self.assertRaises(ValueError) as exc:
717             fdt_util.GetByte(self.node, 'longbytearray')
718         self.assertIn("property 'longbytearray' has list value: expecting a "
719                       'single byte', str(exc.exception))
720
721         with self.assertRaises(ValueError) as exc:
722             fdt_util.GetByte(self.node, 'intval')
723         self.assertIn("property 'intval' has length 4, expecting 1",
724                       str(exc.exception))
725
726     def test_get_bytes(self):
727         """Test getting multiple bytes from a node"""
728         self.assertEqual(bytes([5]), fdt_util.GetBytes(self.node, 'byteval', 1))
729         self.assertEqual(None, fdt_util.GetBytes(self.node, 'missing', 3))
730         self.assertEqual(
731             bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3,  bytes([3])))
732
733         with self.assertRaises(ValueError) as exc:
734             fdt_util.GetBytes(self.node, 'longbytearray', 7)
735         self.assertIn(
736             "Node 'spl-test' property 'longbytearray' has length 9, expecting 7",
737              str(exc.exception))
738
739         self.assertEqual(
740             bytes([0, 0, 0, 1]), fdt_util.GetBytes(self.node, 'intval', 4))
741         self.assertEqual(
742             bytes([3]), fdt_util.GetBytes(self.node, 'missing', 3,  bytes([3])))
743
744     def test_get_phandle_list(self):
745         """Test getting a list of phandles from a node"""
746         dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
747         node = dtb.GetNode('/phandle-source2')
748         self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
749         node = dtb.GetNode('/phandle-source')
750         self.assertEqual([1, 2, 11, 3, 12, 13, 1],
751                          fdt_util.GetPhandleList(node, 'clocks'))
752         self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
753
754     def test_get_data_type(self):
755         """Test getting a value of a particular type from a node"""
756         self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
757         self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
758                                                          str))
759         with self.assertRaises(ValueError):
760             self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
761                                                      bool))
762     def test_fdt_cells_to_cpu(self):
763         """Test getting cells with the correct endianness"""
764         val = self.node.props['intarray'].value
765         self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
766         self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
767
768         dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
769         node1 = dtb2.GetNode('/test1')
770         val = node1.props['reg'].value
771         self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
772
773         node2 = dtb2.GetNode('/test2')
774         val = node2.props['reg'].value
775         self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
776         self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
777                                                                        2))
778         self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
779
780     def test_ensure_compiled(self):
781         """Test a degenerate case of this function (file already compiled)"""
782         dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
783         self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
784
785     def test_ensure_compiled_tmpdir(self):
786         """Test providing a temporary directory"""
787         try:
788             old_outdir = tools.outdir
789             tools.outdir= None
790             tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
791             dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
792                                           tmpdir)
793             self.assertEqual(tmpdir, os.path.dirname(dtb))
794             shutil.rmtree(tmpdir)
795         finally:
796             tools.outdir= old_outdir
797
798     def test_get_phandle_name_offset(self):
799         val = fdt_util.GetPhandleNameOffset(self.node, 'missing')
800         self.assertIsNone(val)
801
802         dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
803         node = dtb.GetNode('/phandle-source')
804         node, name, offset = fdt_util.GetPhandleNameOffset(node,
805                                                            'phandle-name-offset')
806         self.assertEqual('phandle3-target', node.name)
807         self.assertEqual('fred', name)
808         self.assertEqual(123, offset)
809
810 def run_test_coverage(build_dir):
811     """Run the tests and check that we get 100% coverage
812
813     Args:
814         build_dir (str): Directory containing the build output
815     """
816     test_util.run_test_coverage('tools/dtoc/test_fdt.py', None,
817             ['tools/patman/*.py', 'tools/u_boot_pylib/*', '*test_fdt.py'],
818             build_dir)
819
820
821 def run_tests(names, processes):
822     """Run all the test we have for the fdt model
823
824     Args:
825         names (list of str): List of test names provided. Only the first is used
826         processes (int): Number of processes to use (None means as many as there
827             are CPUs on the system. This must be set to 1 when running under
828             the python3-coverage tool
829
830     Returns:
831         int: Return code, 0 on success
832     """
833     test_name = names[0] if names else None
834     result = test_util.run_test_suites(
835         'test_fdt', False, False, False, processes, test_name, None,
836         [TestFdt, TestNode, TestProp, TestFdtUtil])
837
838     return (0 if result.wasSuccessful() else 1)
839
840
841 def main():
842     """Main program for this tool"""
843     parser = ArgumentParser()
844     parser.add_argument('-B', '--build-dir', type=str, default='b',
845                         help='Directory containing the build output')
846     parser.add_argument('-P', '--processes', type=int,
847                         help='set number of processes to use for running tests')
848     parser.add_argument('-t', '--test', action='store_true', dest='test',
849                         default=False, help='run tests')
850     parser.add_argument('-T', '--test-coverage', action='store_true',
851                         default=False,
852                         help='run tests and check for 100% coverage')
853     parser.add_argument('name', nargs='*')
854     args = parser.parse_args()
855
856     # Run our meagre tests
857     if args.test:
858         ret_code = run_tests(args.name, args.processes)
859         return ret_code
860     if args.test_coverage:
861         run_test_coverage(args.build_dir)
862     return 0
863
864 if __name__ == '__main__':
865     sys.exit(main())
This page took 0.065482 seconds and 2 git commands to generate.