Merge tag 'u-boot-atmel-fixes-2021.01-a' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / tools / dtoc / test_fdt.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0+
3 # Copyright (c) 2018 Google, Inc
4 # Written by Simon Glass <sjg@chromium.org>
5 #
6
7 from optparse import OptionParser
8 import glob
9 import os
10 import shutil
11 import sys
12 import tempfile
13 import unittest
14
15 # Bring in the patman libraries
16 our_path = os.path.dirname(os.path.realpath(__file__))
17 sys.path.insert(1, os.path.join(our_path, '..'))
18
19 from dtoc import fdt
20 from dtoc import fdt_util
21 from dtoc.fdt_util import fdt32_to_cpu
22 from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, BytesToValue
23 import libfdt
24 from patman import command
25 from patman import test_util
26 from patman import tools
27
28 def _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)]
49     return prop, [tools.ToChar(x) for x in data]
50
51
52 class 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):
64         tools.FinaliseOutputDir()
65
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))
79
80         node = self.dtb.GetNode('/i2c@0/pmic@9')
81         self.assertTrue(isinstance(node, fdt.Node))
82         self.assertEqual('pmic@9', node.name)
83         self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
84
85         node = self.dtb.GetNode('/')
86         self.assertTrue(isinstance(node, fdt.Node))
87         self.assertEqual(0, node.Offset())
88
89     def testFlush(self):
90         """Check that we can flush the device tree out to its file"""
91         fname = self.dtb._fname
92         with open(fname, 'rb') as fd:
93             data = fd.read()
94         os.remove(fname)
95         with self.assertRaises(IOError):
96             open(fname, 'rb')
97         self.dtb.Flush()
98         with open(fname, 'rb') as fd:
99             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"""
107         self.assertTrue(isinstance(self.dtb.GetContents(), bytearray))
108
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',
114                           'intarray', 'intval', 'longbytearray', 'notstring',
115                           '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:
121             fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
122         self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
123
124     def testGetFdt(self):
125         node = self.dtb.GetNode('/spl-test')
126         self.assertEqual(self.dtb, node.GetFdt())
127
128     def testBytesToValue(self):
129         self.assertEqual(BytesToValue(b'this\0is\0'),
130                          (TYPE_STRING, ['this', 'is']))
131
132 class 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):
141         tools.FinaliseOutputDir()
142
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)
161         with self.assertRaises(libfdt.FdtException):
162             self.node.DeleteProp('missing')
163
164     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
170     def testFindNode(self):
171         """Tests that we can find a node using the FindNode() functoin"""
172         node = self.dtb.GetRoot().FindNode('i2c@0')
173         self.assertEqual('i2c@0', node.name)
174         subnode = node.FindNode('pmic@9')
175         self.assertEqual('pmic@9', subnode.name)
176         self.assertEqual(None, node.FindNode('missing'))
177
178     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
204     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
212
213 class 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):
222         tools.FinaliseOutputDir()
223
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
229     def testMissingNode(self):
230         self.assertEqual(None, self.dtb.GetNode('missing'))
231
232     def testPhandle(self):
233         dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
234         node = dtb.GetNode('/phandle-source2')
235         prop = node.props['clocks']
236         self.assertTrue(fdt32_to_cpu(prop.value) > 0)
237
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         """
246         p = self.fdt.getprop(self.node.Offset(), prop_name)
247         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
286     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))
290         self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(fdt.TYPE_INT))
291         self.assertEqual('', fdt.Prop.GetEmpty(fdt.TYPE_STRING))
292
293     def testGetOffset(self):
294         """Test we can get the offset of a property"""
295         prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
296         self.assertEqual(prop.value, value)
297
298     def testWiden(self):
299         """Test widening of values"""
300         node2 = self.dtb.GetNode('/spl-test2')
301         node3 = self.dtb.GetNode('/spl-test3')
302         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']
320         prop3 = node3.props['longbytearray']
321         self.assertFalse(isinstance(prop2.value, list))
322         self.assertEqual(4, len(prop2.value))
323         self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
324         prop2.Widen(prop)
325         self.assertTrue(isinstance(prop2.value, list))
326         self.assertEqual(9, len(prop2.value))
327         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)
334
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
353     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')
360         self.dtb.Sync(auto_resize=True)
361
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)
368         self.dtb.Sync(auto_resize=False)
369
370         # This should fail since it would need to increase the device-tree size
371         self.node.AddZeroProp('four')
372         with self.assertRaises(libfdt.FdtException) as e:
373             self.dtb.Sync(auto_resize=False)
374         self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
375         self.dtb.Sync(auto_resize=True)
376
377     def testAddNode(self):
378         self.fdt.pack()
379         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)
387
388     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')
404         self.assertEqual(tools.ToBytes(val) + b'\0', data)
405
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']
414         prop.SetData(tools.ToBytes(val))
415         self.dtb.Sync(auto_resize=False)
416         data = self.fdt.getprop(self.node.Offset(), 'string')
417         self.assertEqual(tools.ToBytes(val), data)
418
419         self.node.AddEmptyProp('empty', 5)
420         self.dtb.Sync(auto_resize=True)
421         prop = self.node.props['empty']
422         prop.SetData(tools.ToBytes(val))
423         self.dtb.Sync(auto_resize=False)
424         data = self.fdt.getprop(self.node.Offset(), 'empty')
425         self.assertEqual(tools.ToBytes(val), data)
426
427         self.node.SetData('empty', b'123')
428         self.assertEqual(b'123', prop.bytes)
429
430         # 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
434     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
442     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
463     def testGetFilename(self):
464         """Test the dtb filename can be provided"""
465         self.assertEqual(tools.GetOutputFilename('source.dtb'),
466                          self.dtb.GetFilename())
467
468
469 class 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
480     @classmethod
481     def tearDownClass(cls):
482         tools.FinaliseOutputDir()
483
484     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
513     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
527     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
536     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))
543     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')
549         node1 = dtb2.GetNode('/test1')
550         val = node1.props['reg'].value
551         self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
552
553         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
560     def testEnsureCompiled(self):
561         """Test a degenerate case of this function (file already compiled)"""
562         dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
563         self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
564
565     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
578
579 def 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
585 def 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
595     for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
596         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
605     print(result)
606     for _, err in result.errors:
607         print(err)
608     for _, err in result.failures:
609         print(err)
610
611 if __name__ != '__main__':
612     sys.exit(1)
613
614 parser = OptionParser()
615 parser.add_option('-B', '--build-dir', type='string', default='b',
616         help='Directory containing the build output')
617 parser.add_option('-P', '--processes', type=int,
618                   help='set number of processes to use for running tests')
619 parser.add_option('-t', '--test', action='store_true', dest='test',
620                   default=False, help='run tests')
621 parser.add_option('-T', '--test-coverage', action='store_true',
622                 default=False, help='run tests and check for 100% coverage')
623 (options, args) = parser.parse_args()
624
625 # Run our meagre tests
626 if options.test:
627     RunTests(args)
628 elif options.test_coverage:
629     RunTestCoverage()