xref: /openbmc/u-boot/tools/patman/test_util.py (revision 3d5ced9e22d32112a20f9dc0f5fb1f22ef088079)
1ff1fd6ccSSimon Glass# SPDX-License-Identifier: GPL-2.0+
2ff1fd6ccSSimon Glass#
3ff1fd6ccSSimon Glass# Copyright (c) 2016 Google, Inc
4ff1fd6ccSSimon Glass#
5ff1fd6ccSSimon Glass
6c3f94541SSimon Glassfrom contextlib import contextmanager
7ff1fd6ccSSimon Glassimport glob
8ff1fd6ccSSimon Glassimport os
9ff1fd6ccSSimon Glassimport sys
10ff1fd6ccSSimon Glass
11ff1fd6ccSSimon Glassimport command
12ff1fd6ccSSimon Glass
13c3f94541SSimon Glasstry:
14c3f94541SSimon Glass  from StringIO import StringIO
15c3f94541SSimon Glassexcept ImportError:
16c3f94541SSimon Glass  from io import StringIO
17c3f94541SSimon Glass
18c3f94541SSimon Glass
19ff1fd6ccSSimon Glassdef RunTestCoverage(prog, filter_fname, exclude_list, build_dir, required=None):
20ff1fd6ccSSimon Glass    """Run tests and check that we get 100% coverage
21ff1fd6ccSSimon Glass
22ff1fd6ccSSimon Glass    Args:
23ff1fd6ccSSimon Glass        prog: Program to run (with be passed a '-t' argument to run tests
24ff1fd6ccSSimon Glass        filter_fname: Normally all *.py files in the program's directory will
25ff1fd6ccSSimon Glass            be included. If this is not None, then it is used to filter the
26ff1fd6ccSSimon Glass            list so that only filenames that don't contain filter_fname are
27ff1fd6ccSSimon Glass            included.
28ff1fd6ccSSimon Glass        exclude_list: List of file patterns to exclude from the coverage
29ff1fd6ccSSimon Glass            calculation
30ff1fd6ccSSimon Glass        build_dir: Build directory, used to locate libfdt.py
31ff1fd6ccSSimon Glass        required: List of modules which must be in the coverage report
32ff1fd6ccSSimon Glass
33ff1fd6ccSSimon Glass    Raises:
34ff1fd6ccSSimon Glass        ValueError if the code coverage is not 100%
35ff1fd6ccSSimon Glass    """
36ff1fd6ccSSimon Glass    # This uses the build output from sandbox_spl to get _libfdt.so
37ff1fd6ccSSimon Glass    path = os.path.dirname(prog)
38ff1fd6ccSSimon Glass    if filter_fname:
39ff1fd6ccSSimon Glass        glob_list = glob.glob(os.path.join(path, '*.py'))
40ff1fd6ccSSimon Glass        glob_list = [fname for fname in glob_list if filter_fname in fname]
41ff1fd6ccSSimon Glass    else:
42ff1fd6ccSSimon Glass        glob_list = []
43ff1fd6ccSSimon Glass    glob_list += exclude_list
44ff1fd6ccSSimon Glass    glob_list += ['*libfdt.py', '*site-packages*']
45ff1fd6ccSSimon Glass    cmd = ('PYTHONPATH=$PYTHONPATH:%s/sandbox_spl/tools python-coverage run '
46*11ae93eeSSimon Glass           '--omit "%s" %s -P1 -t' % (build_dir, ','.join(glob_list), prog))
47ff1fd6ccSSimon Glass    os.system(cmd)
48ff1fd6ccSSimon Glass    stdout = command.Output('python-coverage', 'report')
49ff1fd6ccSSimon Glass    lines = stdout.splitlines()
50ff1fd6ccSSimon Glass    if required:
51ff1fd6ccSSimon Glass        # Convert '/path/to/name.py' just the module name 'name'
52ff1fd6ccSSimon Glass        test_set = set([os.path.splitext(os.path.basename(line.split()[0]))[0]
53ff1fd6ccSSimon Glass                        for line in lines if '/etype/' in line])
54ff1fd6ccSSimon Glass        missing_list = required
55ff1fd6ccSSimon Glass        missing_list.difference_update(test_set)
56ff1fd6ccSSimon Glass        if missing_list:
57ff1fd6ccSSimon Glass            print 'Missing tests for %s' % (', '.join(missing_list))
58ff1fd6ccSSimon Glass            print stdout
59ff1fd6ccSSimon Glass            ok = False
60ff1fd6ccSSimon Glass
61ff1fd6ccSSimon Glass    coverage = lines[-1].split(' ')[-1]
62ff1fd6ccSSimon Glass    ok = True
63ff1fd6ccSSimon Glass    print coverage
64ff1fd6ccSSimon Glass    if coverage != '100%':
65ff1fd6ccSSimon Glass        print stdout
66ff1fd6ccSSimon Glass        print ("Type 'python-coverage html' to get a report in "
67ff1fd6ccSSimon Glass               'htmlcov/index.html')
68ff1fd6ccSSimon Glass        print 'Coverage error: %s, but should be 100%%' % coverage
69ff1fd6ccSSimon Glass        ok = False
70ff1fd6ccSSimon Glass    if not ok:
71ff1fd6ccSSimon Glass        raise ValueError('Test coverage failure')
72c3f94541SSimon Glass
73c3f94541SSimon Glass
74c3f94541SSimon Glass# Use this to suppress stdout/stderr output:
75c3f94541SSimon Glass# with capture_sys_output() as (stdout, stderr)
76c3f94541SSimon Glass#   ...do something...
77c3f94541SSimon Glass@contextmanager
78c3f94541SSimon Glassdef capture_sys_output():
79c3f94541SSimon Glass    capture_out, capture_err = StringIO(), StringIO()
80c3f94541SSimon Glass    old_out, old_err = sys.stdout, sys.stderr
81c3f94541SSimon Glass    try:
82c3f94541SSimon Glass        sys.stdout, sys.stderr = capture_out, capture_err
83c3f94541SSimon Glass        yield capture_out, capture_err
84c3f94541SSimon Glass    finally:
85c3f94541SSimon Glass        sys.stdout, sys.stderr = old_out, old_err
86