binman: Allow a single test to be executed
[oweals/u-boot.git] / tools / binman / binman.py
1 #!/usr/bin/env python2
2 # SPDX-License-Identifier: GPL-2.0+
3
4 # Copyright (c) 2016 Google, Inc
5 # Written by Simon Glass <sjg@chromium.org>
6 #
7 # Creates binary images from input files controlled by a description
8 #
9
10 """See README for more information"""
11
12 import glob
13 import os
14 import sys
15 import traceback
16 import unittest
17
18 # Bring in the patman and dtoc libraries
19 our_path = os.path.dirname(os.path.realpath(__file__))
20 for dirname in ['../patman', '../dtoc', '..']:
21     sys.path.insert(0, os.path.join(our_path, dirname))
22
23 # Bring in the libfdt module
24 sys.path.insert(0, 'scripts/dtc/pylibfdt')
25
26 import cmdline
27 import command
28 import control
29
30 def RunTests(debug, args):
31     """Run the functional tests and any embedded doctests
32
33     Args:
34         debug: True to enable debugging, which shows a full stack trace on error
35         args: List of positional args provided to binman. This can hold a test
36             name to execute (as in 'binman -t testSections', for example)
37     """
38     import elf_test
39     import entry_test
40     import fdt_test
41     import ftest
42     import image_test
43     import test
44     import doctest
45
46     result = unittest.TestResult()
47     for module in []:
48         suite = doctest.DocTestSuite(module)
49         suite.run(result)
50
51     sys.argv = [sys.argv[0]]
52     if debug:
53         sys.argv.append('-D')
54
55     # Run the entry tests first ,since these need to be the first to import the
56     # 'entry' module.
57     suite = unittest.TestLoader().loadTestsFromTestCase(entry_test.TestEntry)
58     suite.run(result)
59     test_name = args and args[0] or None
60     for module in (ftest.TestFunctional, fdt_test.TestFdt, elf_test.TestElf,
61                    image_test.TestImage):
62         if test_name:
63             try:
64                 suite = unittest.TestLoader().loadTestsFromName(args[0], module)
65             except AttributeError:
66                 continue
67         else:
68             suite = unittest.TestLoader().loadTestsFromTestCase(module)
69         suite.run(result)
70
71     print result
72     for test, err in result.errors:
73         print test.id(), err
74     for test, err in result.failures:
75         print err, result.failures
76     if result.errors or result.failures:
77       print 'binman tests FAILED'
78       return 1
79     return 0
80
81 def RunTestCoverage():
82     """Run the tests and check that we get 100% coverage"""
83     # This uses the build output from sandbox_spl to get _libfdt.so
84     cmd = ('PYTHONPATH=$PYTHONPATH:%s/sandbox_spl/tools coverage run '
85             '--include "tools/binman/*.py" --omit "*test*,*binman.py" '
86             'tools/binman/binman.py -t' % options.build_dir)
87     os.system(cmd)
88     stdout = command.Output('coverage', 'report')
89     lines = stdout.splitlines()
90
91     test_set= set([os.path.basename(line.split()[0])
92                      for line in lines if '/etype/' in line])
93     glob_list = glob.glob(os.path.join(our_path, 'etype/*.py'))
94     all_set = set([os.path.basename(item) for item in glob_list])
95     missing_list = all_set
96     missing_list.difference_update(test_set)
97     missing_list.remove('_testing.py')
98     coverage = lines[-1].split(' ')[-1]
99     ok = True
100     if missing_list:
101         print 'Missing tests for %s' % (', '.join(missing_list))
102         ok = False
103     if coverage != '100%':
104         print stdout
105         print "Type 'coverage html' to get a report in htmlcov/index.html"
106         print 'Coverage error: %s, but should be 100%%' % coverage
107         ok = False
108     if not ok:
109       raise ValueError('Test coverage failure')
110
111 def RunBinman(options, args):
112     """Main entry point to binman once arguments are parsed
113
114     Args:
115         options: Command-line options
116         args: Non-option arguments
117     """
118     ret_code = 0
119
120     # For testing: This enables full exception traces.
121     #options.debug = True
122
123     if not options.debug:
124         sys.tracebacklimit = 0
125
126     if options.test:
127         ret_code = RunTests(options.debug, args[1:])
128
129     elif options.test_coverage:
130         RunTestCoverage()
131
132     elif options.full_help:
133         pager = os.getenv('PAGER')
134         if not pager:
135             pager = 'more'
136         fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
137                             'README')
138         command.Run(pager, fname)
139
140     else:
141         try:
142             ret_code = control.Binman(options, args)
143         except Exception as e:
144             print 'binman: %s' % e
145             if options.debug:
146                 print
147                 traceback.print_exc()
148             ret_code = 1
149     return ret_code
150
151
152 if __name__ == "__main__":
153     (options, args) = cmdline.ParseArgs(sys.argv)
154     ret_code = RunBinman(options, args)
155     sys.exit(ret_code)