diff --git a/django_coverage_plugin/plugin.py b/django_coverage_plugin/plugin.py index a3e4867..70fa747 100644 --- a/django_coverage_plugin/plugin.py +++ b/django_coverage_plugin/plugin.py @@ -8,6 +8,10 @@ import os.path import re +try: + from coverage.exceptions import NoSource +except ImportError: # for coverage 5.x + from coverage.misc import NoSource import coverage.plugin import django import django.template @@ -303,7 +307,10 @@ def __init__(self, filename): def source(self): if self._source is None: - self._source = read_template_source(self.filename) + try: + self._source = read_template_source(self.filename) + except (IOError, UnicodeError) as exc: + raise NoSource("Couldn't read {}: {}".format(self.filename, exc)) return self._source def lines(self): diff --git a/tests/test_source.py b/tests/test_source.py index 76992d3..6782ec6 100644 --- a/tests/test_source.py +++ b/tests/test_source.py @@ -3,6 +3,11 @@ """Tests of template inheritance for django_coverage_plugin.""" +try: + from coverage.exceptions import NoSource +except ImportError: # for coverage 5.x + from coverage.misc import NoSource + from .plugin_test import DjangoPluginTestCase @@ -64,3 +69,65 @@ def test_customized_extensions(self): self.assert_analysis([1], name="phd.tex", missing=[1]) # The editor leave-behinds are not in the measured files. self.assert_measured_files("main.html", "unused.html", "phd.tex") + + def test_non_utf8_error(self): + # A non-UTF8 text file will raise an error. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + """) + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # Extra file containing a word encoded in CP-1252 + self.make_file(self._path("static/changelog.txt"), bytes=b"sh\xf6n") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html", "static/changelog.txt") + self.assert_analysis([1], name="main.html") + with self.assertRaisesRegexp(NoSource, r"changelog.txt.*invalid start byte"): + self.cov.html_report() + + def test_non_utf8_omitted(self): + # If we omit the directory with the non-UTF8 file, all is well. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + [report] + omit = */static/* + """) + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # Extra file containing a word encoded in CP-1252 + self.make_file(self._path("static/changelog.txt"), bytes=b"sh\xf6n") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html", "static/changelog.txt") + self.assert_analysis([1], name="main.html") + self.cov.html_report() + + def test_non_utf8_ignored(self): + # If we ignore reporting errors, a non-UTF8 text file is fine. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + [report] + ignore_errors = True + """) + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # Extra file containing a word encoded in CP-1252 + self.make_file(self._path("static/changelog.txt"), bytes=b"sh\xf6n") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html", "static/changelog.txt") + self.assert_analysis([1], name="main.html") + self.cov.html_report()