Improve test coverage for tools.

* 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.
This commit is contained in:
Gordon P. Hemsley 2016-08-30 18:43:08 -04:00
parent 7070e1ce7c
commit c9d1a4247f
3 changed files with 99 additions and 9 deletions

View File

@ -4,6 +4,10 @@ from typing import Callable, Optional
from six.moves import range from six.moves import range
import re import re
class TemplateParserException(Exception):
# TODO: Have callers pass in line numbers.
pass
class TokenizerState(object): class TokenizerState(object):
def __init__(self): def __init__(self):
# type: () -> None # type: () -> None
@ -128,7 +132,7 @@ def validate(fn=None, text=None, check_indent=True):
def no_start_tag(token): def no_start_tag(token):
# type: (Token) -> None # type: (Token) -> None
raise Exception(''' raise TemplateParserException('''
No start tag No start tag
fn: %s fn: %s
end tag: end tag:
@ -167,7 +171,7 @@ def validate(fn=None, text=None, check_indent=True):
if end_col != start_col: if end_col != start_col:
problem = 'Bad indentation.' problem = 'Bad indentation.'
if problem: if problem:
raise Exception(''' raise TemplateParserException('''
fn: %s fn: %s
%s %s
start: start:
@ -238,7 +242,7 @@ def get_handlebars_tag(text, i):
while end < len(text) -1 and text[end] != '}': while end < len(text) -1 and text[end] != '}':
end += 1 end += 1
if text[end] != '}' or text[end+1] != '}': if text[end] != '}' or text[end+1] != '}':
raise Exception('Tag missing }}') raise TemplateParserException('Tag missing }}')
s = text[i:end+2] s = text[i:end+2]
return s return s
@ -248,7 +252,7 @@ def get_django_tag(text, i):
while end < len(text) -1 and text[end] != '%': while end < len(text) -1 and text[end] != '%':
end += 1 end += 1
if text[end] != '%' or text[end+1] != '}': if text[end] != '%' or text[end+1] != '}':
raise Exception('Tag missing %}') raise TemplateParserException('Tag missing %}')
s = text[i:end+2] s = text[i:end+2]
return s return s
@ -261,7 +265,7 @@ def get_html_tag(text, i):
quote_count += 1 quote_count += 1
end += 1 end += 1
if end == len(text) or text[end] != '>': if end == len(text) or text[end] != '>':
raise Exception('Tag missing >') raise TemplateParserException('Tag missing >')
s = text[i:end+1] s = text[i:end+1]
return s return s

View File

@ -248,6 +248,9 @@ def build_custom_checkers(by_lang):
# rare; if we find any, they can be added to the exclude list for # rare; if we find any, they can be added to the exclude list for
# this rule. # this rule.
{'pattern': '% [a-zA-Z0-9_.]*\)?$', {'pattern': '% [a-zA-Z0-9_.]*\)?$',
'exclude_line': set([
('tools/tests/test_template_parser.py', '{% foo'),
]),
'description': 'Used % comprehension without a tuple'}, 'description': 'Used % comprehension without a tuple'},
# To avoid json_error(_variable) and json_error(_(variable)) # To avoid json_error(_variable) and json_error(_(variable))
{'pattern': '\Wjson_error\(_\(?\w+\)', {'pattern': '\Wjson_error\(_\(?\w+\)',

View File

@ -6,6 +6,8 @@ import unittest
try: try:
from tools.lib.template_parser import ( from tools.lib.template_parser import (
TemplateParserException,
get_tag_info,
html_tag_tree, html_tag_tree,
is_django_block_tag, is_django_block_tag,
tokenize, tokenize,
@ -16,6 +18,12 @@ except ImportError:
sys.exit(1) sys.exit(1)
class ParserTest(unittest.TestCase): 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): def test_is_django_block_tag(self):
# type: () -> None # type: () -> None
self.assertTrue(is_django_block_tag('block')) self.assertTrue(is_django_block_tag('block'))
@ -54,6 +62,71 @@ class ParserTest(unittest.TestCase):
''' '''
validate(text=my_html) validate(text=my_html)
def test_validate_no_start_tag(self):
# type: () -> None
my_html = '''
foo</p>
'''
self._assert_validate_error('No start tag', text=my_html)
def test_validate_mismatched_tag(self):
# type: () -> None
my_html = '''
<b>foo</i>
'''
self._assert_validate_error('Mismatched tag.', text=my_html)
def test_validate_bad_indentation(self):
# type: () -> None
my_html = '''
<p>
foo
</p>
'''
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 = '''
<b
'''
self._assert_validate_error('Tag missing >', text=my_html)
def test_validate_incomplete_html_tag_2(self):
# type: () -> None
my_html = '''
<a href="
'''
self._assert_validate_error('Tag missing >', text=my_html)
def test_code_blocks(self): def test_code_blocks(self):
# type: () -> None # type: () -> None
@ -74,10 +147,7 @@ class ParserTest(unittest.TestCase):
<code>x = <code>x =
5</code> 5</code>
''' '''
# See https://github.com/python/typeshed/issues/372 self._assert_validate_error('Code tag is split across two lines.', text=my_html)
# for why we have to ingore types here.
with self.assertRaisesRegexp(Exception, 'split across two lines'): # type: ignore
validate(text=my_html)
def test_anchor_blocks(self): def test_anchor_blocks(self):
# type: () -> None # type: () -> None
@ -145,6 +215,19 @@ class ParserTest(unittest.TestCase):
self.assertEqual(token.kind, 'django_end') self.assertEqual(token.kind, 'django_end')
self.assertEqual(token.tag, 'if') self.assertEqual(token.tag, 'if')
def test_get_tag_info(self):
html = '''
<p id="test" class="test1 test2">foo</p>
'''
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): def test_html_tag_tree(self):
# type: () -> None # type: () -> None
html = ''' html = '''