summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBradley Burns <56638814+bradb423@users.noreply.github.com>2022-01-22 20:14:23 +0000
committerGitHub <noreply@github.com>2022-01-22 12:14:23 -0800
commitcbe2e205dac99f20afff4ccdeca21fd10d596565 (patch)
tree565406a74160d301741556397c43473e38459014 /tests
parent2cc2254581dad57719b155b4d349d4f6fdd65d2d (diff)
downloadpython-coveragepy-git-cbe2e205dac99f20afff4ccdeca21fd10d596565.tar.gz
feat: add "lcov" command for generating LCOV reports
* Add LCOV functionality into coverage.py * Add testing for the LCOV reporter * Add documentation for the LCOV reporter
Diffstat (limited to 'tests')
-rw-r--r--tests/test_cmdline.py91
-rw-r--r--tests/test_lcov.py308
2 files changed, 381 insertions, 18 deletions
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index 42f313f8..ad46ded3 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -52,6 +52,10 @@ class BaseCmdLineTest(CoverageTest):
ignore_errors=None, include=None, omit=None, morfs=[], outfile=None,
contexts=None, pretty_print=None, show_contexts=None,
)
+ _defaults.Coverage().lcov_report(
+ ignore_errors=None, include=None, omit=None, morfs=[], outfile=None,
+ contexts=None,
+ )
_defaults.Coverage(
cover_pylib=None, data_suffix=None, timid=None, branch=None,
config_file=True, source=None, include=None, omit=None, debug=None,
@@ -76,6 +80,7 @@ class BaseCmdLineTest(CoverageTest):
cov.html_report.return_value = 50.0
cov.xml_report.return_value = 50.0
cov.json_report.return_value = 50.0
+ cov.lcov_report.return_value = 50.0
return mk
@@ -438,6 +443,49 @@ class CmdLineTest(BaseCmdLineTest):
cov.json_report()
""")
+ def test_lcov(self):
+ # coverage lcov [-i] [--omit DIR,...] [FILE1 FILE2 ...]
+ self.cmd_executes("lcov", """\
+ cov = Coverage()
+ cov.load()
+ cov.lcov_report()
+ """)
+ self.cmd_executes("lcov -i", """\
+ cov = Coverage()
+ cov.load()
+ cov.lcov_report(ignore_errors=True)
+ """)
+ self.cmd_executes("lcov -o mylcov.foo", """\
+ cov = Coverage()
+ cov.load()
+ cov.lcov_report(outfile="mylcov.foo")
+ """)
+ self.cmd_executes("lcov -o -", """\
+ cov = Coverage()
+ cov.load()
+ cov.lcov_report(outfile="-")
+ """)
+ self.cmd_executes("lcov --omit fooey", """\
+ cov = Coverage(omit=["fooey"])
+ cov.load()
+ cov.lcov_report(omit=["fooey"])
+ """)
+ self.cmd_executes("lcov --omit fooey,booey", """\
+ cov = Coverage(omit=["fooey", "booey"])
+ cov.load()
+ cov.lcov_report(omit=["fooey", "booey"])
+ """)
+ self.cmd_executes("lcov -q", """\
+ cov = Coverage(messages=False)
+ cov.load()
+ cov.lcov_report()
+ """)
+ self.cmd_executes("lcov --quiet", """\
+ cov = Coverage(messages=False)
+ cov.load()
+ cov.lcov_report()
+ """)
+
def test_report(self):
# coverage report [-m] [-i] [-o DIR,...] [FILE1 FILE2 ...]
self.cmd_executes("report", """\
@@ -1006,12 +1054,13 @@ class CmdMainTest(CoverageTest):
class CoverageReportingFake:
"""A fake Coverage.coverage test double."""
# pylint: disable=missing-function-docstring
- def __init__(self, report_result, html_result, xml_result, json_report):
+ def __init__(self, report_result, html_result, xml_result, json_report, lcov_result):
self.config = CoverageConfig()
self.report_result = report_result
self.html_result = html_result
self.xml_result = xml_result
self.json_result = json_report
+ self.lcov_result = lcov_result
def set_option(self, optname, optvalue):
self.config.set_option(optname, optvalue)
@@ -1034,28 +1083,34 @@ class CoverageReportingFake:
def json_report(self, *args_unused, **kwargs_unused):
return self.json_result
+ def lcov_report(self, *args_unused, **kwargs_unused):
+ return self.lcov_result
@pytest.mark.parametrize("results, fail_under, cmd, ret", [
# Command-line switch properly checks the result of reporting functions.
- ((20, 30, 40, 50), None, "report --fail-under=19", 0),
- ((20, 30, 40, 50), None, "report --fail-under=21", 2),
- ((20, 30, 40, 50), None, "html --fail-under=29", 0),
- ((20, 30, 40, 50), None, "html --fail-under=31", 2),
- ((20, 30, 40, 50), None, "xml --fail-under=39", 0),
- ((20, 30, 40, 50), None, "xml --fail-under=41", 2),
- ((20, 30, 40, 50), None, "json --fail-under=49", 0),
- ((20, 30, 40, 50), None, "json --fail-under=51", 2),
+ ((20, 30, 40, 50, 60), None, "report --fail-under=19", 0),
+ ((20, 30, 40, 50, 60), None, "report --fail-under=21", 2),
+ ((20, 30, 40, 50, 60), None, "html --fail-under=29", 0),
+ ((20, 30, 40, 50, 60), None, "html --fail-under=31", 2),
+ ((20, 30, 40, 50, 60), None, "xml --fail-under=39", 0),
+ ((20, 30, 40, 50, 60), None, "xml --fail-under=41", 2),
+ ((20, 30, 40, 50, 60), None, "json --fail-under=49", 0),
+ ((20, 30, 40, 50, 60), None, "json --fail-under=51", 2),
+ ((20, 30, 40, 50, 60), None, "lcov --fail-under=59", 0),
+ ((20, 30, 40, 50, 60), None, "lcov --fail-under=61", 2),
# Configuration file setting properly checks the result of reporting.
- ((20, 30, 40, 50), 19, "report", 0),
- ((20, 30, 40, 50), 21, "report", 2),
- ((20, 30, 40, 50), 29, "html", 0),
- ((20, 30, 40, 50), 31, "html", 2),
- ((20, 30, 40, 50), 39, "xml", 0),
- ((20, 30, 40, 50), 41, "xml", 2),
- ((20, 30, 40, 50), 49, "json", 0),
- ((20, 30, 40, 50), 51, "json", 2),
+ ((20, 30, 40, 50, 60), 19, "report", 0),
+ ((20, 30, 40, 50, 60), 21, "report", 2),
+ ((20, 30, 40, 50, 60), 29, "html", 0),
+ ((20, 30, 40, 50, 60), 31, "html", 2),
+ ((20, 30, 40, 50, 60), 39, "xml", 0),
+ ((20, 30, 40, 50, 60), 41, "xml", 2),
+ ((20, 30, 40, 50, 60), 49, "json", 0),
+ ((20, 30, 40, 50, 60), 51, "json", 2),
+ ((20, 30, 40, 50, 60), 59, "lcov", 0),
+ ((20, 30, 40, 50, 60), 61, "lcov", 2),
# Command-line overrides configuration.
- ((20, 30, 40, 50), 19, "report --fail-under=21", 2),
+ ((20, 30, 40, 50, 60), 19, "report --fail-under=21", 2),
])
def test_fail_under(results, fail_under, cmd, ret):
cov = CoverageReportingFake(*results)
diff --git a/tests/test_lcov.py b/tests/test_lcov.py
new file mode 100644
index 00000000..9d2f8ec6
--- /dev/null
+++ b/tests/test_lcov.py
@@ -0,0 +1,308 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
+
+"""Test LCOV-based summary reporting for coverage.py."""
+
+import textwrap
+import coverage
+
+from tests.coveragetest import CoverageTest
+
+
+class LcovTest(CoverageTest):
+ """Tests of the LCOV reports from coverage.py."""
+
+ def create_initial_files(self):
+ """
+ Helper for tests that handles the common ceremony so the tests can
+ show the consequences of changes in the setup.
+ """
+ self.make_file(
+ "main_file.py",
+ """\
+ #!/usr/bin/env python3
+
+ def cuboid_volume(l):
+ return (l*l*l)
+
+ def IsItTrue():
+ return True
+
+ """,
+ )
+
+ self.make_file(
+ "test_file.py",
+ """\
+ #!/usr/bin/env python3
+
+ from main_file import cuboid_volume
+ import unittest
+
+ class TestCuboid(unittest.TestCase):
+ def test_volume(self):
+ self.assertAlmostEqual(cuboid_volume(2),8)
+ self.assertAlmostEqual(cuboid_volume(1),1)
+ self.assertAlmostEqual(cuboid_volume(0),0)
+ self.assertAlmostEqual(cuboid_volume(5.5),166.375)
+
+ """,
+ )
+
+ def get_lcov_report_content(self):
+ """Return the content of the LCOV report."""
+ filename = "coverage.lcov"
+ with open(filename, "r") as file:
+ file_contents = file.read()
+ return file_contents
+
+ def test_lone_file(self):
+ """For a single file with a couple of functions, the lcov should cover
+ the function definitions themselves, but not the returns."""
+ self.make_file(
+ "main_file.py",
+ """\
+ #!/usr/bin/env python3
+
+ def cuboid_volume(l):
+ return (l*l*l)
+
+ def IsItTrue():
+ return True
+
+ """,
+ )
+ expected_result = """\
+ TN:
+ SF:main_file.py
+ DA:3,1,7URou3io0zReBkk69lEb/Q
+ DA:6,1,ilhb4KUfytxtEuClijZPlQ
+ DA:4,0,Xqj6H1iz/nsARMCAbE90ng
+ DA:7,0,LWILTcvARcydjFFyo9qM0A
+ LF:4
+ LH:2
+ end_of_record
+ """
+ expected_result = textwrap.dedent(expected_result)
+ self.assert_doesnt_exist(".coverage")
+ cov = coverage.Coverage(source=["."])
+ self.start_import_stop(cov, "main_file")
+ cov.lcov_report()
+ actual_result = self.get_lcov_report_content()
+ assert expected_result == actual_result
+
+ def test_simple_line_coverage_two_files(self):
+ """Test that line coverage is created when coverage is run,
+ and matches the output of the file below."""
+ self.create_initial_files()
+ self.assert_doesnt_exist(".coverage")
+ cov = coverage.Coverage(source=".")
+ self.start_import_stop(cov, "test_file")
+ cov.lcov_report()
+ self.assert_exists("coverage.lcov")
+ expected_result = """\
+ TN:
+ SF:main_file.py
+ DA:3,1,7URou3io0zReBkk69lEb/Q
+ DA:6,1,ilhb4KUfytxtEuClijZPlQ
+ DA:4,0,Xqj6H1iz/nsARMCAbE90ng
+ DA:7,0,LWILTcvARcydjFFyo9qM0A
+ LF:4
+ LH:2
+ end_of_record
+ TN:
+ SF:test_file.py
+ DA:3,1,R5Rb4IzmjKRgY/vFFc1TRg
+ DA:4,1,E/tvV9JPVDhEcTCkgrwOFw
+ DA:6,1,GP08LPBYJq8EzYveHJy2qA
+ DA:7,1,MV+jSLi6PFEl+WatEAptog
+ DA:8,0,qyqd1mF289dg6oQAQHA+gQ
+ DA:9,0,nmEYd5F1KrxemgC9iVjlqg
+ DA:10,0,jodMK26WYDizOO1C7ekBbg
+ DA:11,0,LtxfKehkX8o4KvC5GnN52g
+ LF:8
+ LH:4
+ end_of_record
+ """
+ expected_result = textwrap.dedent(expected_result)
+ actual_result = self.get_lcov_report_content()
+ assert expected_result == actual_result
+
+ def test_branch_coverage_one_file(self):
+ """Test that the reporter produces valid branch coverage."""
+ self.make_file(
+ "main_file.py",
+ """\
+ #!/usr/bin/env python3
+
+ def is_it_x(x):
+ if x == 3:
+ return x
+ else:
+ return False
+
+ """,
+ )
+ self.assert_doesnt_exist(".coverage")
+ cov = coverage.Coverage(branch=True, source=".")
+ self.start_import_stop(cov, "main_file")
+ cov.lcov_report()
+ self.assert_exists("coverage.lcov")
+ expected_result = """\
+ TN:
+ SF:main_file.py
+ DA:3,1,4MDXMbvwQ3L7va1tsphVzw
+ DA:4,0,MuERA6EYyZNpKPqoJfzwkA
+ DA:5,0,sAyiiE6iAuPMte9kyd0+3g
+ DA:7,0,W/g8GJDAYJkSSurt59Mzfw
+ LF:4
+ LH:1
+ BRDA:5,0,0,-
+ BRDA:7,0,1,-
+ BRF:2
+ BRH:0
+ end_of_record
+ """
+ expected_result = textwrap.dedent(expected_result)
+ actual_result = self.get_lcov_report_content()
+ assert expected_result == actual_result
+
+ def test_branch_coverage_two_files(self):
+ """Test that valid branch coverage is generated
+ in the case of two files."""
+ self.make_file(
+ "main_file.py",
+ """\
+ #!/usr/bin/env python3
+
+ def is_it_x(x):
+ if x == 3:
+ return x
+ else:
+ return False
+
+ """,
+ )
+
+ self.make_file(
+ "test_file.py",
+ """\
+ #!/usr/bin/env python3
+
+ from main_file import *
+ import unittest
+
+ class TestIsItX(unittest.TestCase):
+ def test_is_it_x(self):
+ self.assertEqual(is_it_x(3), 3)
+ self.assertEqual(is_it_x(4), False)
+
+ """,
+ )
+ self.assert_doesnt_exist(".coverage")
+ cov = coverage.Coverage(branch=True, source=".")
+ self.start_import_stop(cov, "test_file")
+ cov.lcov_report()
+ self.assert_exists("coverage.lcov")
+ expected_result = """\
+ TN:
+ SF:main_file.py
+ DA:3,1,4MDXMbvwQ3L7va1tsphVzw
+ DA:4,0,MuERA6EYyZNpKPqoJfzwkA
+ DA:5,0,sAyiiE6iAuPMte9kyd0+3g
+ DA:7,0,W/g8GJDAYJkSSurt59Mzfw
+ LF:4
+ LH:1
+ BRDA:5,0,0,-
+ BRDA:7,0,1,-
+ BRF:2
+ BRH:0
+ end_of_record
+ TN:
+ SF:test_file.py
+ DA:3,1,9TxKIyoBtmhopmlbDNa8FQ
+ DA:4,1,E/tvV9JPVDhEcTCkgrwOFw
+ DA:6,1,C3s/c8C1Yd/zoNG1GnGexg
+ DA:7,1,9qPyWexYysgeKtB+YvuzAg
+ DA:8,0,LycuNcdqoUhPXeuXUTf5lA
+ DA:9,0,FPTWzd68bDx76HN7VHu1wA
+ LF:6
+ LH:4
+ BRDA:0,0,0,1
+ BRDA:7,0,1,1
+ BRF:2
+ BRH:2
+ end_of_record
+ """
+ expected_result = textwrap.dedent(expected_result)
+ actual_result = self.get_lcov_report_content()
+ assert actual_result == expected_result
+
+ def test_half_covered_branch(self):
+ """Test that for a given branch that is only half covered,
+ the block numbers remain the same, and produces valid lcov.
+ """
+ self.make_file(
+ "main_file.py",
+ """\
+ something = True
+
+ if something:
+ print("Yes, something")
+ else:
+ print("No, nothing")
+
+ """,
+ )
+ self.assert_doesnt_exist(".coverage")
+ cov = coverage.Coverage(branch=True, source=".")
+ self.start_import_stop(cov, "main_file")
+ cov.lcov_report()
+ self.assert_exists("coverage.lcov")
+ expected_result = """\
+ TN:
+ SF:main_file.py
+ DA:1,1,N4kbVOlkNI1rqOfCArBClw
+ DA:3,1,CmlqqPf0/H+R/p7/PLEXZw
+ DA:4,1,rE3mWnpoMq2W2sMETVk/uQ
+ DA:6,0,+Aov7ekIts7C96udNDVIIQ
+ LF:4
+ LH:3
+ BRDA:6,0,0,-
+ BRDA:4,0,1,1
+ BRF:2
+ BRH:1
+ end_of_record
+ """
+ expected_result = textwrap.dedent(expected_result)
+ actual_result = self.get_lcov_report_content()
+ assert actual_result == expected_result
+
+ def test_empty_init_files(self):
+ """Test that in the case of an empty __init__.py file, the lcov
+ reporter will note that the file is there, and will note the empty
+ line. It will also note the lack of branches, and the checksum for
+ the line.
+
+ Although there are no lines found, it will note one line as hit.
+ """
+
+ self.make_file("__init__.py", "")
+ self.assert_doesnt_exist(".coverage")
+ cov = coverage.Coverage(branch=True, source=".")
+ self.start_import_stop(cov, "__init__")
+ cov.lcov_report()
+ self.assert_exists("coverage.lcov")
+ expected_result = """\
+ TN:
+ SF:__init__.py
+ DA:1,1,1B2M2Y8AsgTpgAmY7PhCfg
+ LF:0
+ LH:1
+ BRF:0
+ BRH:0
+ end_of_record
+ """
+ expected_result = textwrap.dedent(expected_result)
+ actual_result = self.get_lcov_report_content()
+ assert actual_result == expected_result