| Index: tools/telemetry/third_party/coverage/tests/test_xml.py
|
| diff --git a/tools/telemetry/third_party/coverage/tests/test_xml.py b/tools/telemetry/third_party/coverage/tests/test_xml.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5a6437efa80a030a8552e210790410ab5dcf92bc
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/coverage/tests/test_xml.py
|
| @@ -0,0 +1,320 @@
|
| +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
|
| +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
|
| +
|
| +"""Tests for XML reports from coverage.py."""
|
| +
|
| +import os
|
| +import re
|
| +
|
| +import coverage
|
| +
|
| +from tests.coveragetest import CoverageTest
|
| +from tests.goldtest import CoverageGoldTest
|
| +from tests.goldtest import change_dir, compare
|
| +
|
| +
|
| +class XmlTestHelpers(CoverageTest):
|
| + """Methods to use from XML tests."""
|
| +
|
| + def run_mycode(self):
|
| + """Run mycode.py, so we can report on it."""
|
| + self.make_file("mycode.py", "print('hello')\n")
|
| + self.run_command("coverage run mycode.py")
|
| +
|
| + def run_doit(self):
|
| + """Construct a simple sub-package."""
|
| + self.make_file("sub/__init__.py")
|
| + self.make_file("sub/doit.py", "print('doit!')")
|
| + self.make_file("main.py", "import sub.doit")
|
| + cov = coverage.Coverage()
|
| + self.start_import_stop(cov, "main")
|
| + return cov
|
| +
|
| + def make_tree(self, width, depth, curdir="."):
|
| + """Make a tree of packages.
|
| +
|
| + Makes `width` directories, named d0 .. d{width-1}. Each directory has
|
| + __init__.py, and `width` files, named f0.py .. f{width-1}.py. Each
|
| + directory also has `width` sub-directories, in the same fashion, until
|
| + a depth of `depth` is reached.
|
| +
|
| + """
|
| + if depth == 0:
|
| + return
|
| +
|
| + def here(p):
|
| + """A path for `p` in our currently interesting directory."""
|
| + return os.path.join(curdir, p)
|
| +
|
| + for i in range(width):
|
| + next_dir = here("d{0}".format(i))
|
| + self.make_tree(width, depth-1, next_dir)
|
| + if curdir != ".":
|
| + self.make_file(here("__init__.py"), "")
|
| + for i in range(width):
|
| + filename = here("f{0}.py".format(i))
|
| + self.make_file(filename, "# {0}\n".format(filename))
|
| +
|
| +
|
| +class XmlReportTest(XmlTestHelpers, CoverageTest):
|
| + """Tests of the XML reports from coverage.py."""
|
| +
|
| + def test_default_file_placement(self):
|
| + self.run_mycode()
|
| + self.run_command("coverage xml")
|
| + self.assert_exists("coverage.xml")
|
| +
|
| + def test_argument_affects_xml_placement(self):
|
| + self.run_mycode()
|
| + self.run_command("coverage xml -o put_it_there.xml")
|
| + self.assert_doesnt_exist("coverage.xml")
|
| + self.assert_exists("put_it_there.xml")
|
| +
|
| + def test_config_file_directory_does_not_exist(self):
|
| + self.run_mycode()
|
| + self.run_command("coverage xml -o nonexistent/put_it_there.xml")
|
| + self.assert_doesnt_exist("coverage.xml")
|
| + self.assert_doesnt_exist("put_it_there.xml")
|
| + self.assert_exists("nonexistent/put_it_there.xml")
|
| +
|
| + def test_config_affects_xml_placement(self):
|
| + self.run_mycode()
|
| + self.make_file(".coveragerc", "[xml]\noutput = xml.out\n")
|
| + self.run_command("coverage xml")
|
| + self.assert_doesnt_exist("coverage.xml")
|
| + self.assert_exists("xml.out")
|
| +
|
| + def test_no_data(self):
|
| + # https://bitbucket.org/ned/coveragepy/issue/210
|
| + self.run_command("coverage xml")
|
| + self.assert_doesnt_exist("coverage.xml")
|
| +
|
| + def test_no_source(self):
|
| + # Written while investigating a bug, might as well keep it.
|
| + # https://bitbucket.org/ned/coveragepy/issue/208
|
| + self.make_file("innocuous.py", "a = 4")
|
| + cov = coverage.Coverage()
|
| + self.start_import_stop(cov, "innocuous")
|
| + os.remove("innocuous.py")
|
| + cov.xml_report(ignore_errors=True)
|
| + self.assert_exists("coverage.xml")
|
| +
|
| + def test_filename_format_showing_everything(self):
|
| + cov = self.run_doit()
|
| + cov.xml_report(outfile="-")
|
| + xml = self.stdout()
|
| + doit_line = re_line(xml, "class.*doit")
|
| + self.assertIn('filename="sub/doit.py"', doit_line)
|
| +
|
| + def test_filename_format_including_filename(self):
|
| + cov = self.run_doit()
|
| + cov.xml_report(["sub/doit.py"], outfile="-")
|
| + xml = self.stdout()
|
| + doit_line = re_line(xml, "class.*doit")
|
| + self.assertIn('filename="sub/doit.py"', doit_line)
|
| +
|
| + def test_filename_format_including_module(self):
|
| + cov = self.run_doit()
|
| + import sub.doit # pylint: disable=import-error
|
| + cov.xml_report([sub.doit], outfile="-")
|
| + xml = self.stdout()
|
| + doit_line = re_line(xml, "class.*doit")
|
| + self.assertIn('filename="sub/doit.py"', doit_line)
|
| +
|
| + def test_reporting_on_nothing(self):
|
| + # Used to raise a zero division error:
|
| + # https://bitbucket.org/ned/coveragepy/issue/250
|
| + self.make_file("empty.py", "")
|
| + cov = coverage.Coverage()
|
| + empty = self.start_import_stop(cov, "empty")
|
| + cov.xml_report([empty], outfile="-")
|
| + xml = self.stdout()
|
| + empty_line = re_line(xml, "class.*empty")
|
| + self.assertIn('filename="empty.py"', empty_line)
|
| + self.assertIn('line-rate="1"', empty_line)
|
| +
|
| + def test_empty_file_is_100_not_0(self):
|
| + # https://bitbucket.org/ned/coveragepy/issue/345
|
| + cov = self.run_doit()
|
| + cov.xml_report(outfile="-")
|
| + xml = self.stdout()
|
| + init_line = re_line(xml, 'filename="sub/__init__.py"')
|
| + self.assertIn('line-rate="1"', init_line)
|
| +
|
| +
|
| +class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
|
| + """Tests about the package structure reported in the coverage.xml file."""
|
| +
|
| + def package_and_class_tags(self, cov):
|
| + """Run an XML report on `cov`, and get the package and class tags."""
|
| + self.captured_stdout.truncate(0)
|
| + cov.xml_report(outfile="-")
|
| + packages_and_classes = re_lines(self.stdout(), r"<package |<class ")
|
| + scrubs = r' branch-rate="0"| complexity="0"| line-rate="[\d.]+"'
|
| + return clean("".join(packages_and_classes), scrubs)
|
| +
|
| + def assert_package_and_class_tags(self, cov, result):
|
| + """Check the XML package and class tags from `cov` match `result`."""
|
| + self.assertMultiLineEqual(
|
| + self.package_and_class_tags(cov),
|
| + clean(result)
|
| + )
|
| +
|
| + def test_package_names(self):
|
| + self.make_tree(width=1, depth=3)
|
| + self.make_file("main.py", """\
|
| + from d0.d0 import f0
|
| + """)
|
| + cov = coverage.Coverage(source=".")
|
| + self.start_import_stop(cov, "main")
|
| + self.assert_package_and_class_tags(cov, """\
|
| + <package name=".">
|
| + <class filename="main.py" name="main.py">
|
| + <package name="d0">
|
| + <class filename="d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/f0.py" name="f0.py">
|
| + <package name="d0.d0">
|
| + <class filename="d0/d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/d0/f0.py" name="f0.py">
|
| + """)
|
| +
|
| + def test_package_depth(self):
|
| + self.make_tree(width=1, depth=4)
|
| + self.make_file("main.py", """\
|
| + from d0.d0 import f0
|
| + """)
|
| + cov = coverage.Coverage(source=".")
|
| + self.start_import_stop(cov, "main")
|
| +
|
| + cov.set_option("xml:package_depth", 1)
|
| + self.assert_package_and_class_tags(cov, """\
|
| + <package name=".">
|
| + <class filename="main.py" name="main.py">
|
| + <package name="d0">
|
| + <class filename="d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/d0/__init__.py" name="d0/__init__.py">
|
| + <class filename="d0/d0/d0/__init__.py" name="d0/d0/__init__.py">
|
| + <class filename="d0/d0/d0/f0.py" name="d0/d0/f0.py">
|
| + <class filename="d0/d0/f0.py" name="d0/f0.py">
|
| + <class filename="d0/f0.py" name="f0.py">
|
| + """)
|
| +
|
| + cov.set_option("xml:package_depth", 2)
|
| + self.assert_package_and_class_tags(cov, """\
|
| + <package name=".">
|
| + <class filename="main.py" name="main.py">
|
| + <package name="d0">
|
| + <class filename="d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/f0.py" name="f0.py">
|
| + <package name="d0.d0">
|
| + <class filename="d0/d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/d0/d0/__init__.py" name="d0/__init__.py">
|
| + <class filename="d0/d0/d0/f0.py" name="d0/f0.py">
|
| + <class filename="d0/d0/f0.py" name="f0.py">
|
| + """)
|
| +
|
| + cov.set_option("xml:package_depth", 3)
|
| + self.assert_package_and_class_tags(cov, """\
|
| + <package name=".">
|
| + <class filename="main.py" name="main.py">
|
| + <package name="d0">
|
| + <class filename="d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/f0.py" name="f0.py">
|
| + <package name="d0.d0">
|
| + <class filename="d0/d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/d0/f0.py" name="f0.py">
|
| + <package name="d0.d0.d0">
|
| + <class filename="d0/d0/d0/__init__.py" name="__init__.py">
|
| + <class filename="d0/d0/d0/f0.py" name="f0.py">
|
| + """)
|
| +
|
| +
|
| +def re_lines(text, pat):
|
| + """Return a list of lines that match `pat` in the string `text`."""
|
| + lines = [l for l in text.splitlines(True) if re.search(pat, l)]
|
| + return lines
|
| +
|
| +
|
| +def re_line(text, pat):
|
| + """Return the one line in `text` that matches regex `pat`."""
|
| + lines = re_lines(text, pat)
|
| + assert len(lines) == 1
|
| + return lines[0]
|
| +
|
| +
|
| +def clean(text, scrub=None):
|
| + """Clean text to prepare it for comparison.
|
| +
|
| + Remove text matching `scrub`, and leading whitespace. Convert backslashes
|
| + to forward slashes.
|
| +
|
| + """
|
| + if scrub:
|
| + text = re.sub(scrub, "", text)
|
| + text = re.sub(r"(?m)^\s+", "", text)
|
| + text = re.sub(r"\\", "/", text)
|
| + return text
|
| +
|
| +
|
| +class XmlGoldTest(CoverageGoldTest):
|
| + """Tests of XML reporting that use gold files."""
|
| +
|
| + # TODO: this should move out of html.
|
| + root_dir = 'tests/farm/html'
|
| +
|
| + def test_a_xml_1(self):
|
| + self.output_dir("out/xml_1")
|
| +
|
| + with change_dir("src"):
|
| + # pylint: disable=import-error
|
| + cov = coverage.Coverage()
|
| + cov.start()
|
| + import a # pragma: nested
|
| + cov.stop() # pragma: nested
|
| + cov.xml_report(a, outfile="../out/xml_1/coverage.xml")
|
| + source_path = coverage.files.relative_directory().rstrip('/')
|
| +
|
| + compare("gold_x_xml", "out/xml_1", scrubs=[
|
| + (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
|
| + (r' version="[-.\w]+"', ' version="VERSION"'),
|
| + (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
|
| + (r'/coverage.readthedocs.org/?[-.\w/]*', '/coverage.readthedocs.org/VER'),
|
| + ])
|
| +
|
| + def test_a_xml_2(self):
|
| + self.output_dir("out/xml_2")
|
| +
|
| + with change_dir("src"):
|
| + # pylint: disable=import-error
|
| + cov = coverage.Coverage(config_file="run_a_xml_2.ini")
|
| + cov.start()
|
| + import a # pragma: nested
|
| + cov.stop() # pragma: nested
|
| + cov.xml_report(a)
|
| + source_path = coverage.files.relative_directory().rstrip('/')
|
| +
|
| + compare("gold_x_xml", "out/xml_2", scrubs=[
|
| + (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
|
| + (r' version="[-.\w]+"', ' version="VERSION"'),
|
| + (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
|
| + (r'/coverage.readthedocs.org/?[-.\w/]*', '/coverage.readthedocs.org/VER'),
|
| + ])
|
| +
|
| + def test_y_xml_branch(self):
|
| + self.output_dir("out/y_xml_branch")
|
| +
|
| + with change_dir("src"):
|
| + # pylint: disable=import-error
|
| + cov = coverage.Coverage(branch=True)
|
| + cov.start()
|
| + import y # pragma: nested
|
| + cov.stop() # pragma: nested
|
| + cov.xml_report(y, outfile="../out/y_xml_branch/coverage.xml")
|
| + source_path = coverage.files.relative_directory().rstrip('/')
|
| +
|
| + compare("gold_y_xml_branch", "out/y_xml_branch", scrubs=[
|
| + (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'),
|
| + (r' version="[-.\w]+"', ' version="VERSION"'),
|
| + (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % source_path),
|
| + (r'/coverage.readthedocs.org/?[-.\w/]*', '/coverage.readthedocs.org/VER'),
|
| + ])
|
|
|