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 12import glob 13import os 14import sys 15import traceback 16import unittest 17 18# Bring in the patman and dtoc libraries 19our_path = os.path.dirname(os.path.realpath(__file__)) 20for dirname in ['../patman', '../dtoc', '..']: 21 sys.path.insert(0, os.path.join(our_path, dirname)) 22 23# Bring in the libfdt module 24sys.path.insert(0, 'scripts/dtc/pylibfdt') 25 26import cmdline 27import command 28import control 29 30def 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 81def 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 111def 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 152if __name__ == "__main__": 153 (options, args) = cmdline.ParseArgs(sys.argv) 154 ret_code = RunBinman(options, args) 155 sys.exit(ret_code) 156