From c9d1a4247fec58815a3ea0f73aa333c051d0ea2b Mon Sep 17 00:00:00 2001 From: "Gordon P. Hemsley" Date: Tue, 30 Aug 2016 18:43:08 -0400 Subject: [PATCH] Improve test coverage for tools. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace generic Exception with TemplateParserException. * Add tests to cover many of the uncovered lines in tools/lib/template_parser.py. * Add an exclusion line to the naïve pattern for checking for missing tuples in format strings, to keep the linter happy. --- tools/lib/template_parser.py | 14 +++-- tools/lint-all | 3 + tools/tests/test_template_parser.py | 91 +++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/tools/lib/template_parser.py b/tools/lib/template_parser.py index 59870b31b0..f323f4947f 100644 --- a/tools/lib/template_parser.py +++ b/tools/lib/template_parser.py @@ -4,6 +4,10 @@ from typing import Callable, Optional from six.moves import range import re +class TemplateParserException(Exception): + # TODO: Have callers pass in line numbers. + pass + class TokenizerState(object): def __init__(self): # type: () -> None @@ -128,7 +132,7 @@ def validate(fn=None, text=None, check_indent=True): def no_start_tag(token): # type: (Token) -> None - raise Exception(''' + raise TemplateParserException(''' No start tag fn: %s end tag: @@ -167,7 +171,7 @@ def validate(fn=None, text=None, check_indent=True): if end_col != start_col: problem = 'Bad indentation.' if problem: - raise Exception(''' + raise TemplateParserException(''' fn: %s %s start: @@ -238,7 +242,7 @@ def get_handlebars_tag(text, i): while end < len(text) -1 and text[end] != '}': end += 1 if text[end] != '}' or text[end+1] != '}': - raise Exception('Tag missing }}') + raise TemplateParserException('Tag missing }}') s = text[i:end+2] return s @@ -248,7 +252,7 @@ def get_django_tag(text, i): while end < len(text) -1 and text[end] != '%': end += 1 if text[end] != '%' or text[end+1] != '}': - raise Exception('Tag missing %}') + raise TemplateParserException('Tag missing %}') s = text[i:end+2] return s @@ -261,7 +265,7 @@ def get_html_tag(text, i): quote_count += 1 end += 1 if end == len(text) or text[end] != '>': - raise Exception('Tag missing >') + raise TemplateParserException('Tag missing >') s = text[i:end+1] return s diff --git a/tools/lint-all b/tools/lint-all index 83500cb9d1..e1ab512c85 100755 --- a/tools/lint-all +++ b/tools/lint-all @@ -248,6 +248,9 @@ def build_custom_checkers(by_lang): # rare; if we find any, they can be added to the exclude list for # this rule. {'pattern': '% [a-zA-Z0-9_.]*\)?$', + 'exclude_line': set([ + ('tools/tests/test_template_parser.py', '{% foo'), + ]), 'description': 'Used % comprehension without a tuple'}, # To avoid json_error(_variable) and json_error(_(variable)) {'pattern': '\Wjson_error\(_\(?\w+\)', diff --git a/tools/tests/test_template_parser.py b/tools/tests/test_template_parser.py index 392c92c675..d63b8caf1e 100644 --- a/tools/tests/test_template_parser.py +++ b/tools/tests/test_template_parser.py @@ -6,6 +6,8 @@ import unittest try: from tools.lib.template_parser import ( + TemplateParserException, + get_tag_info, html_tag_tree, is_django_block_tag, tokenize, @@ -16,6 +18,12 @@ except ImportError: sys.exit(1) class ParserTest(unittest.TestCase): + def _assert_validate_error(self, error, fn=None, text=None, check_indent=True): + # See https://github.com/python/typeshed/issues/372 + # for why we have to ingore types here. + with self.assertRaisesRegexp(TemplateParserException, error): # type: ignore + validate(fn=fn, text=text, check_indent=check_indent) + def test_is_django_block_tag(self): # type: () -> None self.assertTrue(is_django_block_tag('block')) @@ -54,6 +62,71 @@ class ParserTest(unittest.TestCase): ''' validate(text=my_html) + def test_validate_no_start_tag(self): + # type: () -> None + my_html = ''' + foo

+ ''' + self._assert_validate_error('No start tag', text=my_html) + + def test_validate_mismatched_tag(self): + # type: () -> None + my_html = ''' + foo + ''' + self._assert_validate_error('Mismatched tag.', text=my_html) + + def test_validate_bad_indentation(self): + # type: () -> None + my_html = ''' +

+ foo +

+ ''' + self._assert_validate_error('Bad indentation.', text=my_html, check_indent=True) + + def test_validate_incomplete_handlebars_tag_1(self): + # type: () -> None + my_html = ''' + {{# foo + ''' + self._assert_validate_error('Tag missing }}', text=my_html) + + def test_validate_incomplete_handlebars_tag_2(self): + # type: () -> None + my_html = ''' + {{# foo } + ''' + self._assert_validate_error('Tag missing }}', text=my_html) + + def test_validate_incomplete_django_tag_1(self): + # type: () -> None + my_html = ''' + {% foo + ''' + self._assert_validate_error('Tag missing %}', text=my_html) + + def test_validate_incomplete_django_tag_2(self): + # type: () -> None + my_html = ''' + {% foo % + ''' + self._assert_validate_error('Tag missing %}', text=my_html) + + def test_validate_incomplete_html_tag_1(self): + # type: () -> None + my_html = ''' + ', text=my_html) + + def test_validate_incomplete_html_tag_2(self): + # type: () -> None + my_html = ''' + foo

+ ''' + + start_tag, end_tag = tokenize(html) + + start_tag_info = get_tag_info(start_tag) + end_tag_info = get_tag_info(end_tag) + + self.assertEqual(start_tag_info.text(), 'p.test1.test2#test') + self.assertEqual(end_tag_info.text(), 'p') + def test_html_tag_tree(self): # type: () -> None html = '''