blob: c296468f9210efc33c7e758de825b42224c68b87 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2019 The Emscripten Authors. All rights reserved.
# Emscripten is available under two separate licenses, the MIT license and the
# University of Illinois/NCSA Open Source License. Both these licenses can be
# found in the LICENSE file.
"""
This is the Emscripten coverage tool.
Usage: emcoverage.py <help|reset|report|html|xml|COMMAND> ...
Special commands:
- help: show this message
- reset: remove all gathered coverage information
- report: show a quick overview of gathered coverage information
- html: generate coverage as a set of HTML files in ./htmlcov/
- xml: generate XML coverage report in ./coverage.xml
Otherwise, you can run any python script or Emscripten command, for example:
- emcoverage.py ./tests/runner.py wasm0
- emcoverage.py emcc file1.c file2.c
Running a command under emcoverage.py will collect the code coverage
information. Every run under emcoverage.py is additive, and no coverage
information from previous runs is erased, unless explicitly done via
emcoverage.py reset.
To display the gathered coverage information, use one of the three subcommands:
report, html, xml.
"""
import errno
import os
import shutil
import sys
import uuid
from glob import glob
import coverage.cmdline
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
def main():
# We hack sys.executable to point to this file, which is executable via #! line.
# Emscripten uses sys.executable to populate shared.PYTHON, which is used to
# invoke all python subprocesses. By making this script run all python subprocesses,
# all of them will execute under the watchful eye of emcoverage.py, and resulting
# in their code coverage being tracked.
sys.executable = os.path.abspath(__file__)
os.environ['EMSDK_PYTHON'] = sys.executable
store = os.path.join(SCRIPT_DIR, 'coverage')
if len(sys.argv) < 2 or sys.argv[1] == 'help':
print(__doc__.replace('emcoverage.py', sys.argv[0]).strip())
return
if sys.argv[1] == 'reset':
shutil.rmtree(store)
return
if sys.argv[1] in ('html', 'report', 'xml'):
old_argv = sys.argv
sys.argv = ['coverage', 'combine'] + glob(os.path.join(store, '*'))
try:
coverage.cmdline.main()
except SystemExit:
pass
sys.argv = old_argv + ['-i']
return coverage.cmdline.main()
if not os.path.exists(sys.argv[1]):
# If argv[1] is not a file path, instead try to interpret it as an emscripten command.
# This allows `emcoverage.py emcc` or `emcoverage.py embuilder` to work.
sys.argv[1] = os.path.join(os.path.dirname(sys.executable), '..', sys.argv[1] + '.py')
try:
os.mkdir(store)
except OSError as e:
if e.errno != errno.EEXIST:
raise
os.environ['COVERAGE_FILE'] = os.path.join(store, str(uuid.uuid4()))
sys.argv[0:1] = ['coverage', 'run', '--parallel-mode', '--']
return coverage.cmdline.main()
if __name__ == '__main__':
sys.exit(main())