Index: tools/telemetry/third_party/coverage/tests/test_parser.py |
diff --git a/tools/telemetry/third_party/coverage/tests/test_parser.py b/tools/telemetry/third_party/coverage/tests/test_parser.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..84b9a214607affa14d22e59d8428425433d5e144 |
--- /dev/null |
+++ b/tools/telemetry/third_party/coverage/tests/test_parser.py |
@@ -0,0 +1,208 @@ |
+# 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 coverage.py's code parsing.""" |
+ |
+import textwrap |
+ |
+from tests.coveragetest import CoverageTest |
+ |
+from coverage import env |
+from coverage.misc import NotPython |
+from coverage.parser import PythonParser |
+ |
+ |
+class PythonParserTest(CoverageTest): |
+ """Tests for coverage.py's Python code parsing.""" |
+ |
+ run_in_temp_dir = False |
+ |
+ def parse_source(self, text): |
+ """Parse `text` as source, and return the `PythonParser` used.""" |
+ if env.PY2: |
+ text = text.decode("ascii") |
+ text = textwrap.dedent(text) |
+ parser = PythonParser(text=text, exclude="nocover") |
+ parser.parse_source() |
+ return parser |
+ |
+ def test_exit_counts(self): |
+ parser = self.parse_source("""\ |
+ # check some basic branch counting |
+ class Foo: |
+ def foo(self, a): |
+ if a: |
+ return 5 |
+ else: |
+ return 7 |
+ |
+ class Bar: |
+ pass |
+ """) |
+ self.assertEqual(parser.exit_counts(), { |
+ 2:1, 3:1, 4:2, 5:1, 7:1, 9:1, 10:1 |
+ }) |
+ |
+ def test_generator_exit_counts(self): |
+ # https://bitbucket.org/ned/coveragepy/issue/324/yield-in-loop-confuses-branch-coverage |
+ parser = self.parse_source("""\ |
+ def gen(input): |
+ for n in inp: |
+ yield (i * 2 for i in range(n)) |
+ |
+ list(gen([1,2,3])) |
+ """) |
+ self.assertEqual(parser.exit_counts(), { |
+ 1:1, # def -> list |
+ 2:2, # for -> yield; for -> exit |
+ 3:2, # yield -> for; genexp exit |
+ 5:1, # list -> exit |
+ }) |
+ |
+ def test_try_except(self): |
+ parser = self.parse_source("""\ |
+ try: |
+ a = 2 |
+ except ValueError: |
+ a = 4 |
+ except ZeroDivideError: |
+ a = 6 |
+ except: |
+ a = 8 |
+ b = 9 |
+ """) |
+ self.assertEqual(parser.exit_counts(), { |
+ 1: 1, 2:1, 3:1, 4:1, 5:1, 6:1, 7:1, 8:1, 9:1 |
+ }) |
+ |
+ def test_excluded_classes(self): |
+ parser = self.parse_source("""\ |
+ class Foo: |
+ def __init__(self): |
+ pass |
+ |
+ if 0: # nocover |
+ class Bar: |
+ pass |
+ """) |
+ self.assertEqual(parser.exit_counts(), { |
+ 1:0, 2:1, 3:1 |
+ }) |
+ |
+ def test_missing_branch_to_excluded_code(self): |
+ parser = self.parse_source("""\ |
+ if fooey: |
+ a = 2 |
+ else: # nocover |
+ a = 4 |
+ b = 5 |
+ """) |
+ self.assertEqual(parser.exit_counts(), { 1:1, 2:1, 5:1 }) |
+ parser = self.parse_source("""\ |
+ def foo(): |
+ if fooey: |
+ a = 3 |
+ else: |
+ a = 5 |
+ b = 6 |
+ """) |
+ self.assertEqual(parser.exit_counts(), { 1:1, 2:2, 3:1, 5:1, 6:1 }) |
+ parser = self.parse_source("""\ |
+ def foo(): |
+ if fooey: |
+ a = 3 |
+ else: # nocover |
+ a = 5 |
+ b = 6 |
+ """) |
+ self.assertEqual(parser.exit_counts(), { 1:1, 2:1, 3:1, 6:1 }) |
+ |
+ def test_indentation_error(self): |
+ msg = ( |
+ "Couldn't parse '<code>' as Python source: " |
+ "'unindent does not match any outer indentation level' at line 3" |
+ ) |
+ with self.assertRaisesRegex(NotPython, msg): |
+ _ = self.parse_source("""\ |
+ 0 spaces |
+ 2 |
+ 1 |
+ """) |
+ |
+ def test_token_error(self): |
+ msg = "Couldn't parse '<code>' as Python source: 'EOF in multi-line string' at line 1" |
+ with self.assertRaisesRegex(NotPython, msg): |
+ _ = self.parse_source("""\ |
+ ''' |
+ """) |
+ |
+ |
+class ParserFileTest(CoverageTest): |
+ """Tests for coverage.py's code parsing from files.""" |
+ |
+ def parse_file(self, filename): |
+ """Parse `text` as source, and return the `PythonParser` used.""" |
+ # pylint: disable=attribute-defined-outside-init |
+ parser = PythonParser(filename=filename, exclude="nocover") |
+ self.statements, self.excluded = parser.parse_source() |
+ return parser |
+ |
+ def test_line_endings(self): |
+ text = """\ |
+ # check some basic branch counting |
+ class Foo: |
+ def foo(self, a): |
+ if a: |
+ return 5 |
+ else: |
+ return 7 |
+ |
+ class Bar: |
+ pass |
+ """ |
+ counts = { 2:1, 3:1, 4:2, 5:1, 7:1, 9:1, 10:1 } |
+ name_endings = (("unix", "\n"), ("dos", "\r\n"), ("mac", "\r")) |
+ for fname, newline in name_endings: |
+ fname = fname + ".py" |
+ self.make_file(fname, text, newline=newline) |
+ parser = self.parse_file(fname) |
+ self.assertEqual( |
+ parser.exit_counts(), |
+ counts, |
+ "Wrong for %r" % fname |
+ ) |
+ |
+ def test_encoding(self): |
+ self.make_file("encoded.py", """\ |
+ coverage = "\xe7\xf6v\xear\xe3g\xe9" |
+ """) |
+ parser = self.parse_file("encoded.py") |
+ self.assertEqual(parser.exit_counts(), {1: 1}) |
+ |
+ def test_missing_line_ending(self): |
+ # Test that the set of statements is the same even if a final |
+ # multi-line statement has no final newline. |
+ # https://bitbucket.org/ned/coveragepy/issue/293 |
+ |
+ self.make_file("normal.py", """\ |
+ out, err = subprocess.Popen( |
+ [sys.executable, '-c', 'pass'], |
+ stdout=subprocess.PIPE, |
+ stderr=subprocess.PIPE).communicate() |
+ """) |
+ |
+ self.parse_file("normal.py") |
+ self.assertEqual(self.statements, set([1])) |
+ |
+ self.make_file("abrupt.py", """\ |
+ out, err = subprocess.Popen( |
+ [sys.executable, '-c', 'pass'], |
+ stdout=subprocess.PIPE, |
+ stderr=subprocess.PIPE).communicate()""") # no final newline. |
+ |
+ # Double-check that some test helper wasn't being helpful. |
+ with open("abrupt.py") as f: |
+ self.assertEqual(f.read()[-1], ")") |
+ |
+ self.parse_file("abrupt.py") |
+ self.assertEqual(self.statements, set([1])) |