"""Unit Tests for error reporting."""
__revision__ = "$Rev: 496 $"
__author__ = "Christoph Zwerschke "
__copyright__ = "Copyright 2006, Christoph Zwerschke"
import sys
from os.path import join as joinpath
from tempfile import mkdtemp
from shutil import rmtree
import kid
from kid.test.util import raises
# Error tracking is only fully supported in Python 2.4
# because we need the CurrentLineNumber attribute of Expat
python24 = sys.version_info[:2] >= (2, 4)
def setup_module(module):
global tmpdir
tmpdir = mkdtemp(prefix='kid_test_error_')
kid.path.insert(tmpdir)
def teardown_module(module):
kid.path.remove(tmpdir)
rmtree(tmpdir)
class KidFileWriter:
test_number = 0
def __init__(self):
KidFileWriter.test_number += 1
self.file_number = 0
def name(self):
return 'test_error_%d_%d' % (self.test_number, self.file_number)
def filename(self, full=False):
filename = '%s.kid' % self.name()
if full:
filename = joinpath(tmpdir, filename)
return filename
def write(self, xml):
self.file_number += 1
open(self.filename(True), 'w').write(xml)
def test_xml_error():
"""Check that erroneous XML is reported."""
from xml.parsers.expat import ExpatError
page = """\
title
oops
That's all, folks.
"""
kid.Template(page)
page = page.replace('', '')
e = str(raises(ExpatError, kid.Template, source=page))
assert 'Error parsing XML' in e
assert 'mismatched tag: line 3, column 24' in e
assert page.splitlines()[2] in e # erroneous line
assert "\n%25s\n" % "^" in e # offset pointer
assert 'html' not in e
assert 'title' not in e
assert 'folks' not in e
page = """\
title
"""
t = kid.Template(source=page, xml="ok
")
from xml.parsers.expat import ExpatError
content = """\
start
this &is wrong
end
"""
t = kid.Template(source=page, xml=content)
e = str(raises(ExpatError, t.serialize))
assert 'Error parsing XML' in e
assert 'not well-formed (invalid token): line 2, column 16' in e
assert content.splitlines()[1] in e
assert "\n%17s\n" % "^" in e
assert 'html' not in e
assert 'start' not in e
assert 'end' not in e
def test_xml_long_line():
"""Check intelligent truncating of long XML error lines."""
from xml.parsers.expat import ExpatError
page = 'x' + 9999*'x'
e = str(raises(ExpatError, kid.Template, page))
assert 'Error parsing XML' in e
assert 'mismatched tag: line 1, column 6' in e
assert ('\nx' + 68*'x') in e
assert "\n%7s\n" % "^" in e
page = '' + 9999*'x' + ''
e = str(raises(ExpatError, kid.Template, page))
assert 'Error parsing XML' in e
assert 'mismatched tag: line 1, column 10004' in e
assert ('\n' + 72*'x' + '') in e
assert "\n%75s\n" % "^" in e
page = '' + 9999*'x' + '' + 9999*'x'
e = str(raises(ExpatError, kid.Template, page))
assert 'Error parsing XML' in e
assert 'mismatched tag: line 1, column 10004' in e
assert ('\n' + 36*'x' + '' + 36*'x') in e
assert "\n%39s\n" % "^" in e
def test_xml_filename_error():
"""Check that erroneous XML filename is reported."""
f = KidFileWriter()
f.write("This is XML")
t = kid.Template(file=f.filename())
f.write("This is not XML")
from xml.parsers.expat import ExpatError
e = str(raises(ExpatError, kid.Template, file=f.filename()))
assert 'Error parsing XML' in e
assert f.filename() in e
assert 'This is not XML' in e
assert 'syntax error: line 1, column 0' in e
assert '\n^\n' in e
def test_layout_error():
"""Check that erroneous py:layout expressions are reported."""
page = ''
# because py:layout is dynamic, the template can be created
# but the error should show up when we try to serialize the template
t = kid.Template(source=page)
from kid.template_util import TemplateLayoutError
e = str(raises(TemplateLayoutError, t.serialize))
assert 'not defined' in e
assert 'while processing layout=' in e
assert 'no_layout' in e
def test_extends_error():
"""Check that erroneous py:extends expressions are reported."""
page = ''
# because py:extends is not dynamic, the template cannot be created
from kid.template_util import TemplateExtendsError
e = str(raises(TemplateExtendsError, kid.Template, source=page))
assert 'not defined' in e
assert 'while processing extends=' in e
assert 'no_extends' in e
def test_attr_error():
"""Check that erroneous py:attrs expressions are reported."""
page = """\
"""
t = kid.Template(source=page % "abc=123, def=789")
s = t.serialize()
assert 'abc="123"' in s and 'def="789"' in s
from kid.template_util import TemplateAttrsError
t = kid.Template(source=page % "abc=123, 456=789")
e = str(raises(TemplateAttrsError, t.serialize))
assert 'invalid' in e
assert 'while processing attrs=' in e
assert 'abc=123, 456=789' in e
t = kid.Template(source=page % "{'mickey':'mouse'}")
s = t.serialize()
assert 'mickey="mouse"' in s
t = kid.Template(source=page % "mickey mouse")
e = str(raises(TemplateAttrsError, t.serialize))
assert 'while processing attrs=' in e
assert 'mickey mouse' in e
t = kid.Template(source=page % "{mickey:mouse}")
e = str(raises(TemplateAttrsError, t.serialize))
assert 'not defined' in e
assert 'mickey' in e and 'mouse' in e
def test_tracking_1():
"""Check error tracking when compiling a Kid template."""
from kid.compiler import compile_file
f = KidFileWriter()
xml = """
compilation fails
the expression ${1/0} can be compiled
the expression ${1//0} can be compiled
the expression ${1///0} cannot be compiled
the expression ${1+1} can be compiled
"""
for call in (compile_file, kid.load_template, kid.Template):
f.write(xml)
e = str(raises(SyntaxError,
call, file=f.filename(call == compile_file)))
assert 'invalid syntax (%s.py, line ' % f.name() in e
assert ' 1///0' in e and ' ^\n' in e
assert '1/0' not in e and '1//0' not in e and '1+1' not in e
assert 'can be compiled' not in e
if python24:
assert 'Error location in template file ' in e
assert f.filename() in e
assert 'on line 5 between columns 8 and 54:' in e
assert 'the expression ${1///0} cannot be compiled' in e
assert 'xml>' not in e and 'title>' not in e
assert 'p1>' not in e and 'p2>' not in e and 'p4>' not in e
assert 'compilation fails' not in e
xml = """
compilation fails
"""
for call in (compile_file, kid.load_template, kid.Template):
f.write(xml)
e = str(raises(SyntaxError,
call, file=f.filename(call == compile_file)))
assert 'invalid syntax (%s.py, line ' % f.name() in e
assert 'oops = 1///0' in e and ' ^\n' in e
assert 'ok =' not in e
assert '1/0' not in e and '1//0' not in e and '1+1' not in e
if python24:
assert 'Error location in template file ' in e
assert f.filename() in e
assert 'between line 10, column 8 and line 13, column 8:' in e
assert ' oops = 1///0' in e
assert 'xml>' not in e and 'title>' not in e
assert 'compilation fails' not in e
def test_tracking_2():
"""Check error tracking when importing a Kid template."""
from kid.compiler import compile_file
f = KidFileWriter()
xml = """
import fails
"""
f.write(xml)
try:
e = compile_file(file=f.filename(True))
except Exception:
e = None
assert e == True, 'This file cannot be compiled properly.'
for call in (kid.load_template, kid.Template):
f.write(xml)
e = str(raises(ZeroDivisionError, call, file=f.filename()))
assert 'integer division or modulo by zero' in e
if python24:
assert 'Error location in template file ' in e
assert f.filename() in e
assert 'between line 4, column 8 and line 5, column 8:' in e
assert '' in e
assert 'xml>' not in e and 'title>' not in e
assert 'import fails' not in e
def test_tracking_3():
"""Check error tracking when executing a Kid template."""
f = KidFileWriter()
xml = """
execution fails
the expression ${1/2} can be evaluated
the expression ${1/0} cannot be evaluated
"""
f.write(xml)
t = kid.Template(file=f.filename())
def execute_template_method(t, n):
if n == 1:
import StringIO
output = StringIO.StringIO()
t.write(file=output)
ret = output.getvalue()
output.close()
elif n == 2:
ret = list(t.generate())
else:
ret = t.serialize()
return ret
for n in range(3):
e = str(raises(ZeroDivisionError, execute_template_method, t, n))
assert 'integer division or modulo by zero' in e
if python24 and n < 2:
assert 'Error location in template file ' in e
assert f.filename() in e
assert 'on line 4 between columns 8 and 53:' in e
assert 'the expression ${1/0} cannot be evaluated' in e
assert 'xml>' not in e and 'title>' not in e
assert 'execution fails' not in e
xml = """
execution fails
"""
f.write(xml)
t = kid.Template(file=f.filename())
e = str(raises(ZeroDivisionError, t.serialize))
assert 'integer division or modulo by zero' in e
if python24:
assert 'Error location in template file ' in e
assert f.filename() in e
assert 'between line 4, column 8 and line 5, column 8:' in e
assert '' not in e and 'title>' not in e
assert 'execution fails' not in e
xml = """
execution fails
test1
test2
"""
f.write(xml)
t = kid.Template(file=f.filename())
e = str(raises(ZeroDivisionError, t.serialize))
assert 'integer division or modulo by zero' in e
if python24:
assert 'Error location in template file ' in e
assert f.filename() in e
assert 'between line 4, column 22 and line 5, column 8:' in e
assert ' py:content="1/0"' in e
assert '"1/2"' not in e
assert 'xml>' not in e and 'title>' not in e
assert 'p1>' not in e and 'h1>' not in e
assert 'h2>' not in e
assert 'execution fails' not in e
def test_tracking_4():
"""Check error tracking when compiling a Kid template."""
from kid.compiler import compile_file
f = KidFileWriter()
xml = """
execution fails
test
"""
f.write(xml)
t = kid.Template(file=f.filename())
e = raises(UnicodeDecodeError, t.serialize)
assert e.__class__.__name__ == UnicodeDecodeError.__name__
assert e.__class__.__module__ == UnicodeDecodeError.__module__
assert hasattr(e, 'reason') \
and e.reason == "ordinal not in range(128)"
e = str(e)
assert "can't decode byte 0xe4 in position 1" in e
assert "ordinal not in range(128)" in e
assert '\nError in code generated from template file ' in e
assert f.filename() in e
assert 'execution fails' not in e