diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2023-01-07 22:54:05 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2023-01-07 22:54:05 -0500 |
commit | 08564c09144b2223be808f49b001c8856966bd46 (patch) | |
tree | 3bfe15a660292e1463448988c95de683a4a553cd /tests | |
parent | 65aad086ccccea33f0ff9535c9612e1b4b6712ce (diff) | |
download | python-coveragepy-git-08564c09144b2223be808f49b001c8856966bd46.tar.gz |
mypy: templite.py test_templite.py
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_templite.py | 96 |
1 files changed, 48 insertions, 48 deletions
diff --git a/tests/test_templite.py b/tests/test_templite.py index d2e98479..e34f7169 100644 --- a/tests/test_templite.py +++ b/tests/test_templite.py @@ -3,8 +3,13 @@ """Tests for coverage.templite.""" +from __future__ import annotations + import re +from types import SimpleNamespace +from typing import Any, ContextManager, Dict, List, Optional + import pytest from coverage.templite import Templite, TempliteSyntaxError, TempliteValueError @@ -13,23 +18,18 @@ from tests.coveragetest import CoverageTest # pylint: disable=possibly-unused-variable -class AnyOldObject: - """Simple testing object. - - Use keyword arguments in the constructor to set attributes on the object. - - """ - def __init__(self, **attrs): - for n, v in attrs.items(): - setattr(self, n, v) - class TempliteTest(CoverageTest): """Tests for Templite.""" run_in_temp_dir = False - def try_render(self, text, ctx=None, result=None): + def try_render( + self, + text: str, + ctx: Optional[Dict[str, Any]] = None, + result: Optional[str] = None, + ) -> None: """Render `text` through `ctx`, and it had better be `result`. Result defaults to None so we can shorten the calls where we expect @@ -42,30 +42,30 @@ class TempliteTest(CoverageTest): assert result is not None assert actual == result - def assertSynErr(self, msg): + def assertSynErr(self, msg: str) -> ContextManager[None]: """Assert that a `TempliteSyntaxError` will happen. A context manager, and the message should be `msg`. """ pat = "^" + re.escape(msg) + "$" - return pytest.raises(TempliteSyntaxError, match=pat) + return pytest.raises(TempliteSyntaxError, match=pat) # type: ignore - def test_passthrough(self): + def test_passthrough(self) -> None: # Strings without variables are passed through unchanged. assert Templite("Hello").render() == "Hello" assert Templite("Hello, 20% fun time!").render() == "Hello, 20% fun time!" - def test_variables(self): + def test_variables(self) -> None: # Variables use {{var}} syntax. self.try_render("Hello, {{name}}!", {'name':'Ned'}, "Hello, Ned!") - def test_undefined_variables(self): + def test_undefined_variables(self) -> None: # Using undefined names is an error. with pytest.raises(Exception, match="'name'"): self.try_render("Hi, {{name}}!") - def test_pipes(self): + def test_pipes(self) -> None: # Variables can be filtered with pipes. data = { 'name': 'Ned', @@ -77,7 +77,7 @@ class TempliteTest(CoverageTest): # Pipes can be concatenated. self.try_render("Hello, {{name|upper|second}}!", data, "Hello, E!") - def test_reusability(self): + def test_reusability(self) -> None: # A single Templite can be used more than once with different data. globs = { 'upper': lambda x: x.upper(), @@ -88,30 +88,30 @@ class TempliteTest(CoverageTest): assert template.render({'name':'Ned'}) == "This is NED!" assert template.render({'name':'Ben'}) == "This is BEN!" - def test_attribute(self): + def test_attribute(self) -> None: # Variables' attributes can be accessed with dots. - obj = AnyOldObject(a="Ay") + obj = SimpleNamespace(a="Ay") self.try_render("{{obj.a}}", locals(), "Ay") - obj2 = AnyOldObject(obj=obj, b="Bee") + obj2 = SimpleNamespace(obj=obj, b="Bee") self.try_render("{{obj2.obj.a}} {{obj2.b}}", locals(), "Ay Bee") - def test_member_function(self): + def test_member_function(self) -> None: # Variables' member functions can be used, as long as they are nullary. - class WithMemberFns(AnyOldObject): + class WithMemberFns(SimpleNamespace): """A class to try out member function access.""" - def ditto(self): + def ditto(self) -> str: """Return twice the .txt attribute.""" - return self.txt + self.txt + return self.txt + self.txt # type: ignore obj = WithMemberFns(txt="Once") self.try_render("{{obj.ditto}}", locals(), "OnceOnce") - def test_item_access(self): + def test_item_access(self) -> None: # Variables' items can be used. d = {'a':17, 'b':23} self.try_render("{{d.a}} < {{d.b}}", locals(), "17 < 23") - def test_loops(self): + def test_loops(self) -> None: # Loops work like in Django. nums = [1,2,3,4] self.try_render( @@ -120,7 +120,7 @@ class TempliteTest(CoverageTest): "Look: 1, 2, 3, 4, done." ) # Loop iterables can be filtered. - def rev(l): + def rev(l: List[int]) -> List[int]: """Return the reverse of `l`.""" l = l[:] l.reverse() @@ -132,21 +132,21 @@ class TempliteTest(CoverageTest): "Look: 4, 3, 2, 1, done." ) - def test_empty_loops(self): + def test_empty_loops(self) -> None: self.try_render( "Empty: {% for n in nums %}{{n}}, {% endfor %}done.", {'nums':[]}, "Empty: done." ) - def test_multiline_loops(self): + def test_multiline_loops(self) -> None: self.try_render( "Look: \n{% for n in nums %}\n{{n}}, \n{% endfor %}done.", {'nums':[1,2,3]}, "Look: \n\n1, \n\n2, \n\n3, \ndone." ) - def test_multiple_loops(self): + def test_multiple_loops(self) -> None: self.try_render( "{% for n in nums %}{{n}}{% endfor %} and " + "{% for n in nums %}{{n}}{% endfor %}", @@ -154,7 +154,7 @@ class TempliteTest(CoverageTest): "123 and 123" ) - def test_comments(self): + def test_comments(self) -> None: # Single-line comments work: self.try_render( "Hello, {# Name goes here: #}{{name}}!", @@ -166,7 +166,7 @@ class TempliteTest(CoverageTest): {'name':'Ned'}, "Hello, Ned!" ) - def test_if(self): + def test_if(self) -> None: self.try_render( "Hi, {% if ned %}NED{% endif %}{% if ben %}BEN{% endif %}!", {'ned': 1, 'ben': 0}, @@ -193,10 +193,10 @@ class TempliteTest(CoverageTest): "Hi, NEDBEN!" ) - def test_complex_if(self): - class Complex(AnyOldObject): + def test_complex_if(self) -> None: + class Complex(SimpleNamespace): """A class to try out complex data access.""" - def getit(self): + def getit(self): # type: ignore """Return it.""" return self.it obj = Complex(it={'x':"Hello", 'y': 0}) @@ -210,7 +210,7 @@ class TempliteTest(CoverageTest): "@XS!" ) - def test_loop_if(self): + def test_loop_if(self) -> None: self.try_render( "@{% for n in nums %}{% if n %}Z{% endif %}{{n}}{% endfor %}!", {'nums': [0,1,2]}, @@ -227,7 +227,7 @@ class TempliteTest(CoverageTest): "X!" ) - def test_nested_loops(self): + def test_nested_loops(self) -> None: self.try_render( "@" + "{% for n in nums %}" + @@ -238,7 +238,7 @@ class TempliteTest(CoverageTest): "@a0b0c0a1b1c1a2b2c2!" ) - def test_whitespace_handling(self): + def test_whitespace_handling(self) -> None: self.try_render( "@{% for n in nums %}\n" + " {% for a in abc %}{{a}}{{n}}{% endfor %}\n" + @@ -268,7 +268,7 @@ class TempliteTest(CoverageTest): ) self.try_render(" hello ", {}, " hello ") - def test_eat_whitespace(self): + def test_eat_whitespace(self) -> None: self.try_render( "Hey!\n" + "{% joined %}\n" + @@ -286,14 +286,14 @@ class TempliteTest(CoverageTest): "Hey!\n@XYa0XYb0XYc0XYa1XYb1XYc1XYa2XYb2XYc2!\n" ) - def test_non_ascii(self): + def test_non_ascii(self) -> None: self.try_render( "{{where}} ollǝɥ", { 'where': 'ǝɹǝɥʇ' }, "ǝɹǝɥʇ ollǝɥ" ) - def test_exception_during_evaluation(self): + def test_exception_during_evaluation(self) -> None: # TypeError: Couldn't evaluate {{ foo.bar.baz }}: regex = "^Couldn't evaluate None.bar$" with pytest.raises(TempliteValueError, match=regex): @@ -301,7 +301,7 @@ class TempliteTest(CoverageTest): "Hey {{foo.bar.baz}} there", {'foo': None}, "Hey ??? there" ) - def test_bad_names(self): + def test_bad_names(self) -> None: with self.assertSynErr("Not a valid name: 'var%&!@'"): self.try_render("Wat: {{ var%&!@ }}") with self.assertSynErr("Not a valid name: 'filter%&!@'"): @@ -309,17 +309,17 @@ class TempliteTest(CoverageTest): with self.assertSynErr("Not a valid name: '@'"): self.try_render("Wat: {% for @ in x %}{% endfor %}") - def test_bogus_tag_syntax(self): + def test_bogus_tag_syntax(self) -> None: with self.assertSynErr("Don't understand tag: 'bogus'"): self.try_render("Huh: {% bogus %}!!{% endbogus %}??") - def test_malformed_if(self): + def test_malformed_if(self) -> None: with self.assertSynErr("Don't understand if: '{% if %}'"): self.try_render("Buh? {% if %}hi!{% endif %}") with self.assertSynErr("Don't understand if: '{% if this or that %}'"): self.try_render("Buh? {% if this or that %}hi!{% endif %}") - def test_malformed_for(self): + def test_malformed_for(self) -> None: with self.assertSynErr("Don't understand for: '{% for %}'"): self.try_render("Weird: {% for %}loop{% endfor %}") with self.assertSynErr("Don't understand for: '{% for x from y %}'"): @@ -327,7 +327,7 @@ class TempliteTest(CoverageTest): with self.assertSynErr("Don't understand for: '{% for x, y in z %}'"): self.try_render("Weird: {% for x, y in z %}loop{% endfor %}") - def test_bad_nesting(self): + def test_bad_nesting(self) -> None: with self.assertSynErr("Unmatched action tag: 'if'"): self.try_render("{% if x %}X") with self.assertSynErr("Mismatched end tag: 'for'"): @@ -335,7 +335,7 @@ class TempliteTest(CoverageTest): with self.assertSynErr("Too many ends: '{% endif %}'"): self.try_render("{% if x %}{% endif %}{% endif %}") - def test_malformed_end(self): + def test_malformed_end(self) -> None: with self.assertSynErr("Don't understand end: '{% end if %}'"): self.try_render("{% if x %}X{% end if %}") with self.assertSynErr("Don't understand end: '{% endif now %}'"): |