Home | History | Annotate | Download | only in binman
      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 (at] 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)
    156