helpers.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
  2. # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
  3. """Helpers for coverage.py tests."""
  4. import os
  5. import subprocess
  6. import sys
  7. from coverage import env
  8. from coverage.misc import output_encoding
  9. def run_command(cmd):
  10. """Run a command in a sub-process.
  11. Returns the exit status code and the combined stdout and stderr.
  12. """
  13. if env.PY2 and isinstance(cmd, unicode):
  14. cmd = cmd.encode(sys.getfilesystemencoding())
  15. # In some strange cases (PyPy3 in a virtualenv!?) the stdout encoding of
  16. # the subprocess is set incorrectly to ascii. Use an environment variable
  17. # to force the encoding to be the same as ours.
  18. sub_env = dict(os.environ)
  19. encoding = output_encoding()
  20. if encoding:
  21. sub_env['PYTHONIOENCODING'] = encoding
  22. proc = subprocess.Popen(
  23. cmd,
  24. shell=True,
  25. env=sub_env,
  26. stdin=subprocess.PIPE, stdout=subprocess.PIPE,
  27. stderr=subprocess.STDOUT
  28. )
  29. output, _ = proc.communicate()
  30. status = proc.returncode
  31. # Get the output, and canonicalize it to strings with newlines.
  32. if not isinstance(output, str):
  33. output = output.decode(output_encoding())
  34. output = output.replace('\r', '')
  35. return status, output
  36. class CheckUniqueFilenames(object):
  37. """Asserts the uniqueness of file names passed to a function."""
  38. def __init__(self, wrapped):
  39. self.filenames = set()
  40. self.wrapped = wrapped
  41. @classmethod
  42. def hook(cls, cov, method_name):
  43. """Replace a method with our checking wrapper."""
  44. method = getattr(cov, method_name)
  45. hook = cls(method)
  46. setattr(cov, method_name, hook.wrapper)
  47. return hook
  48. def wrapper(self, filename, *args, **kwargs):
  49. """The replacement method. Check that we don't have dupes."""
  50. assert filename not in self.filenames, (
  51. "File name %r passed to %r twice" % (filename, self.wrapped)
  52. )
  53. self.filenames.add(filename)
  54. ret = self.wrapped(filename, *args, **kwargs)
  55. return ret