#!/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 ... 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())